对`operator<<(std::ostream&, /* class with non-type template parameters */&)' 的未定义引用
undefined reference to `operator<<(std::ostream&, /* class with non-type template parameters */&)'
对于家庭作业,我必须使用非类型模板参数制作一个 class,然后添加 std::
(i
/o
)stream
运算符。但是,当我尝试编译 clang++ 时出现链接器错误:
$ clang++ -o foo ./*.cpp -std=c++11 -Wall -Wextra -Wpedantic -Wconversion -Wnon-virtual-dtor
/tmp/16_15-8cda65.o: In function `main':
main.cpp:(.text+0x108): undefined reference to `operator<<(std::ostream&, Screen<9ul, 9ul> const&)'
clang: error: linker command failed with exit code 1 (use -v to see invocation)
我知道模板声明和定义必须在同一个翻译单元中,这里有很多问题和答案都指出了这一点。
我的节选代码如下:
main.cpp:
#include <iostream>
#include "Screen.h"
int main()
{
Screen<9,9> smile =
{
{0,0,0,1,1,1,0,0,0},
{0,1,1,0,0,0,1,1,0},
{0,1,0,0,0,0,0,1,0},
{1,0,0,1,0,1,0,0,1},
{1,0,0,0,0,0,0,0,1},
{1,0,1,0,0,0,1,0,1},
{0,1,0,1,1,1,0,1,0},
{0,1,1,0,0,0,1,1,0},
{0,0,0,1,1,1,0,0,0}
};
std::cout << smile;
return 0;
}
Screen.h:
#ifndef SCREEN_H
#define SCREEN_H
#include <iostream>
#include <array>
#include <initializer_list>
#include <cstddef>
template <std::size_t W, std::size_t H>
class Screen
{
/////////////
// FRIENDS //
/////////////
friend std::ostream& operator<<(std::ostream&, const Screen<W,H>&);
public:
// declarations of ctors, public members, etc.
private:
//////////
// DATA //
//////////
std::array<std::array<bool,W>,H> pixels;
};
/////////////////
// NON-MEMBERS //
/////////////////
// ostream operator
template <std::size_t W, std::size_t H>
std::ostream& operator<<(std::ostream&, const Screen<W,H>&);
#include "Screen_impl.h"
#endif
Screen_impl.h:
#ifndef SCREEN_IMPL_H
#define SCREEN_IMPL_H
#include <iostream>
#include <array>
#include <algorithm>
#include <stdexcept>
#include <initializer_list>
#include <cstddef>
// definitions...
/////////////////
// NON-MEMBERS //
/////////////////
// ostream operator
template <std::size_t W, std::size_t H>
std::ostream& operator<<(std::ostream& lhs, const Screen<W,H>& rhs)
{
for (auto y = rhs.pixels.cbegin(); y < rhs.pixels.cend(); ++y)
{
for (auto x = y->cbegin(); x < y->cend(); ++x)
{
if (*x)
lhs << '#';
else
lhs << ' ';
}
lhs << std::endl;
}
return lhs;
}
#endif
在class中声明的operator<<
函数不是一个函数模板,但你稍后定义了一个函数模板。因此,您声明的实体与您定义的实体不同。
您需要将 class 中的函数模板声明为
template <std::size_t WX, std::size_t HX>
friend std::ostream& operator<<(std::ostream&, const Screen<WX, HX>&);
请注意,模板参数的命名需要与 class 模板参数不同,以避免阴影。
您也可以只在 class 中定义 operator<<
。
这位朋友算
template <std::size_t W, std::size_t H>
class Screen
{
/////////////
// FRIENDS //
/////////////
friend std::ostream& operator<<(std::ostream&, const Screen<W,H>&);
//
不是模板运算符。
所以它作为模板运算符的定义是无效的。也就是说,它不是 class 定义中声明的非模板友元运算符的定义。
因此,编译器发出错误,指出未找到运算符的定义。
将友元运算符的定义放在class定义中。在这种情况下,此定义将用于 class.
的每个特化
否则,您将需要为 class 的每个具体特化分别定义运算符。
这是一个演示程序。
#include <iostream>
#include <iterator>
#include <numeric>
template <size_t N>
class Array
{
private:
int a[N];
public:
Array()
{
std::iota( std::begin( a ), std::end( a ), 0 );
}
friend std::ostream & operator <<( std::ostream &os, const Array &a )
{
for ( const auto &item : a.a ) os <<item << ' ';
return os;
}
};
int main()
{
std::cout << Array<1>() << '\n';
std::cout << Array<2>() << '\n';
std::cout << Array<3>() << '\n';
std::cout << Array<4>() << '\n';
std::cout << Array<5>() << '\n';
return 0;
}
它的输出是
0
0 1
0 1 2
0 1 2 3
0 1 2 3 4
对于家庭作业,我必须使用非类型模板参数制作一个 class,然后添加 std::
(i
/o
)stream
运算符。但是,当我尝试编译 clang++ 时出现链接器错误:
$ clang++ -o foo ./*.cpp -std=c++11 -Wall -Wextra -Wpedantic -Wconversion -Wnon-virtual-dtor
/tmp/16_15-8cda65.o: In function `main':
main.cpp:(.text+0x108): undefined reference to `operator<<(std::ostream&, Screen<9ul, 9ul> const&)'
clang: error: linker command failed with exit code 1 (use -v to see invocation)
我知道模板声明和定义必须在同一个翻译单元中,这里有很多问题和答案都指出了这一点。
我的节选代码如下:
main.cpp:
#include <iostream>
#include "Screen.h"
int main()
{
Screen<9,9> smile =
{
{0,0,0,1,1,1,0,0,0},
{0,1,1,0,0,0,1,1,0},
{0,1,0,0,0,0,0,1,0},
{1,0,0,1,0,1,0,0,1},
{1,0,0,0,0,0,0,0,1},
{1,0,1,0,0,0,1,0,1},
{0,1,0,1,1,1,0,1,0},
{0,1,1,0,0,0,1,1,0},
{0,0,0,1,1,1,0,0,0}
};
std::cout << smile;
return 0;
}
Screen.h:
#ifndef SCREEN_H
#define SCREEN_H
#include <iostream>
#include <array>
#include <initializer_list>
#include <cstddef>
template <std::size_t W, std::size_t H>
class Screen
{
/////////////
// FRIENDS //
/////////////
friend std::ostream& operator<<(std::ostream&, const Screen<W,H>&);
public:
// declarations of ctors, public members, etc.
private:
//////////
// DATA //
//////////
std::array<std::array<bool,W>,H> pixels;
};
/////////////////
// NON-MEMBERS //
/////////////////
// ostream operator
template <std::size_t W, std::size_t H>
std::ostream& operator<<(std::ostream&, const Screen<W,H>&);
#include "Screen_impl.h"
#endif
Screen_impl.h:
#ifndef SCREEN_IMPL_H
#define SCREEN_IMPL_H
#include <iostream>
#include <array>
#include <algorithm>
#include <stdexcept>
#include <initializer_list>
#include <cstddef>
// definitions...
/////////////////
// NON-MEMBERS //
/////////////////
// ostream operator
template <std::size_t W, std::size_t H>
std::ostream& operator<<(std::ostream& lhs, const Screen<W,H>& rhs)
{
for (auto y = rhs.pixels.cbegin(); y < rhs.pixels.cend(); ++y)
{
for (auto x = y->cbegin(); x < y->cend(); ++x)
{
if (*x)
lhs << '#';
else
lhs << ' ';
}
lhs << std::endl;
}
return lhs;
}
#endif
在class中声明的operator<<
函数不是一个函数模板,但你稍后定义了一个函数模板。因此,您声明的实体与您定义的实体不同。
您需要将 class 中的函数模板声明为
template <std::size_t WX, std::size_t HX>
friend std::ostream& operator<<(std::ostream&, const Screen<WX, HX>&);
请注意,模板参数的命名需要与 class 模板参数不同,以避免阴影。
您也可以只在 class 中定义 operator<<
。
这位朋友算
template <std::size_t W, std::size_t H>
class Screen
{
/////////////
// FRIENDS //
/////////////
friend std::ostream& operator<<(std::ostream&, const Screen<W,H>&);
//
不是模板运算符。
所以它作为模板运算符的定义是无效的。也就是说,它不是 class 定义中声明的非模板友元运算符的定义。
因此,编译器发出错误,指出未找到运算符的定义。
将友元运算符的定义放在class定义中。在这种情况下,此定义将用于 class.
的每个特化否则,您将需要为 class 的每个具体特化分别定义运算符。
这是一个演示程序。
#include <iostream>
#include <iterator>
#include <numeric>
template <size_t N>
class Array
{
private:
int a[N];
public:
Array()
{
std::iota( std::begin( a ), std::end( a ), 0 );
}
friend std::ostream & operator <<( std::ostream &os, const Array &a )
{
for ( const auto &item : a.a ) os <<item << ' ';
return os;
}
};
int main()
{
std::cout << Array<1>() << '\n';
std::cout << Array<2>() << '\n';
std::cout << Array<3>() << '\n';
std::cout << Array<4>() << '\n';
std::cout << Array<5>() << '\n';
return 0;
}
它的输出是
0
0 1
0 1 2
0 1 2 3
0 1 2 3 4