【发布时间】:2012-06-07 20:42:09
【问题描述】:
在我的代码中,我的函数模板包含依赖于某些模板参数的 lambda 表达式。最近我遇到了链接器错误,可能是由于我的 g++ 编译器的更新,但不幸的是,我不知道具体情况。
我将举一个小例子来说明这个问题。因为这是一个链接器问题,我们必须创建几个文件来演示它。我们有common.hpp,它包含一个通用模板函数,两个模块a.cpp/a.hpp 和b.cpp/b.hpp 使用该函数,还有一个main.cpp 模块包含main 函数。
// common.hpp
#include <algorithm>
template <class Iterator, typename Iterator::value_type x>
void
my_transform(Iterator begin, Iterator end)
{
std::transform(begin, end, begin,
[] (typename Iterator::value_type y) { return x+y; });
}
文件a.cpp:
// a.cpp
#include "common.hpp"
#include "a.hpp"
void a(std::vector<int>& vec)
{
my_transform<std::vector<int>::iterator, 5>(vec.begin(), vec.end());
}
文件a.hpp
#include <vector>
void a(std::vector<int>& vec);
文件b.cpp:
// b.cpp
#include "common.hpp"
#include "b.hpp"
void b(std::vector<int>& vec)
{
my_transform<std::vector<int>::iterator, 5>(vec.begin(), vec.end());
}
文件b.hpp
#include <vector>
void b(std::vector<int>& vec);
文件main.cpp
int main() { return 0; }
如果我编译和链接使用
g++-4.7 -std=c++11 -c a.cpp
g++-4.7 -std=c++11 -c b.cpp
g++-4.7 -std=c++11 -c main.cpp
g++ a.o b.o main.o
我收到multiple-definition 错误:
b.cpp:(.text+0x30): multiple definition of `void my_transform<__gnu_cxx::__normal_iterator<int*, std::vector<int, std::allocator<int> > >, 17>(__gnu_cxx::__normal_iterator<int*, std::vector<int, std::allocator<int> > >, __gnu_cxx::__normal_iterator<int*, std::vector<int, std::allocator<int> > >)::{lambda(int)#1}::operator int (*)(int)() const'
a.o:a.cpp:(.text+0x30): first defined here
基本上,它表示 lambda 表达式已经在 a 中定义。好的。如果我将 b 中的模板参数从 5 更改为 7,一切正常。
问题:
- 这是我应该期待的还是
g++中的错误?我很确定我是用早期版本的 debian 软件包g++-4.7编译了这段代码。 - 除了不使用 lambda 之外,还有其他解决方法吗?我认为,如果生成的符号是静态的,则不会有任何问题。 更新:解决方法:将 my_transform 设为
static或inline。
这个问题不是很重要。 “不要在这里使用 lambdas”方法没有问题,但我很好奇。 :)
【问题讨论】:
-
使 my_transform 内联,您在这里遇到了 ODR。
-
@Dani 不这么认为。函数模板明确允许有多个定义,只要它们本质上是相同的。
-
@Dani:我完全不确定他是否违反了 ODR。该函数是一个模板,这有很大的不同。
-
这看起来像是编译器端的一个错误,即生成带有
operator()的 lambda 未标记为内联。 -
是的,在我看来像是一个编译器错误。
标签: c++ templates c++11 g++ multiple-definition-error