这个问题在这里已有答案:
我正在尝试将iostream运算符实现为可变参数类模板的友元函数。
#include <utility>
#include <iostream>
template<typename... Args>
class StudentInformation {
public:
//friend class Student;
using Members = std::tuple<Args...>;
Members members;
const size_t numArgs{ sizeof...(Args) };
StudentInformation( Args&&... args ) : members{ std::make_tuple<Args...>( std::move( args )... ) } {}
const StudentInformation<Args...>& operator() ( Args... args ) {
members = std::make_tuple<Args>( std::forward<Args>( args )... );
return *this;
}
const StudentInformation<Args...> operator() ( Args... args ) const {
members = std::make_tuple<Args>( std::forward<Args>( args )... );
return *this;
}
friend std::ostream& operator<< ( std::ostream& out, const StudentInformation& c );
friend std::istream& operator>> ( std::istream& in, StudentInformation& c );
};
template<typename... T>
std::ostream& operator<<( std::ostream& out, const StudentInformation<T...>& c ) {
const size_t numArgs = c.numArgs;
for( size_t idx = 0; idx < numArgs; idx++ )
out << std::get<idx>( c.members ) << " ";
return out;
}
template<typename... T>
std::istream& operator>>( std::istream& in, StudentInformation<T...>& c ) {
const size_t numArgs = c.numArgs;
for( size_t idx = 0; idx < numArgs; idx++ )
in >> std::get<idx>( c.members );
return in;
}
由于某种原因,我仍然收到链接器错误。即使在头文件中定义了重载,我仍然会收到链接器错误,就好像它们是在cpp文件中定义的一样。有什么想法吗?
即使我尝试这种方法:首先声明类的原型,然后声明重载运算符的原型,然后声明类,然后定义朋友重载运算符:
#include <utility>
#include <iostream>
template<typename... Args>
class StudentInfo;
template<typename... Args>
std::ostream& operator<<( std::ostream& out, const StudentInfo<Args...>& c );
template<typename... Args>
std::istream& operator>>( std::istream& in, StudentInfo<Args...>& c );
template<typename... Args>
class StudentInfo {
public:
//friend class Student;
using Members = std::tuple<Args...>;
Members members;
const size_t numArgs{ sizeof...(Args) };
StudentInfo( Args&&... args ) : members{ std::make_tuple<Args...>( std::move( args )... ) } {}
const StudentInfo<Args...>& operator() ( Args... args ) {
members = std::make_tuple<Args>( std::forward<Args>( args )... );
return *this;
}
const StudentInfo<Args...> operator() ( Args... args ) const {
members = std::make_tuple<Args>( std::forward<Args>( args )... );
return *this;
}
friend std::ostream& operator<< ( std::ostream& out, const StudentInfo& c );
friend std::istream& operator>> ( std::istream& in, StudentInfo& c );
};
template<typename... T>
std::ostream& operator<<( std::ostream& out, const StudentInfo<T...>& c ) {
const size_t numArgs = c.numArgs;
for( size_t idx = 0; idx < numArgs; idx++ )
out << std::get<idx>( c.members ) << " ";
return out;
}
template<typename... T>
std::istream& operator>>( std::istream& in, StudentInfo<T...>& c ) {
const size_t numArgs = c.numArgs;
for( size_t idx = 0; idx < numArgs; idx++ )
in >> std::get<idx>( c.members );
return in;
}
我仍然收到链接器错误。我可以把这些作为课程的一部分;但我不想要那种行为。我希望它们在课外定义。目前的情况;现在班上的所有内容都是公开的,仅用于测试,但一旦这个课程按预期工作;其中的一切都将是私人的,因为这个班级将成为另一个班级的朋友;拥有类可以访问其所有私人信息。我不知道如何解决或解决此链接器错误问题。
1>main.obj : error LNK2019: unresolved external symbol "class std::basic_ostream<char,struct std::char_traits<char> > & __cdecl operator<<(class std::basic_ostream<char,struct std::char_traits<char> > &,class StudentInfo<class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >,class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >,int,class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >,class std::vector<int,class std::allocator<int> > > const &)" (??6@YAAAV?$basic_ostream@DU?$char_traits@D@std@@@std@@AAV01@ABV?$StudentInfo@V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@V12@HV12@V?$vector@HV?$allocator@H@std@@@2@@@@Z) referenced in function _main
这是经典之作。
当你编译main()
(比如在“main.cpp”中)时,你有
std::cout << studentA << '\n';
其中studentA
是StudentInformation<std::string, std::string, int, std::string, std::vector<int>>
。
因此,编译器准备一个中间文件,为operator<<()
请求(调用)StudentInformation<std::string, std::string, int, std::string, std::vector<int>>
。
应该实现operator<<()
编译其他cpp文件,比如说“operators.cpp”。
但是编译“operator.cpp”时,编译器不知道需要operator<<()
的StudentInformation<std::string, std::string, int, std::string, std::vector<int>>
。所以没有实现它。
链接器接收生成的编译“main.cpp”和“operators.cpp”的中间文件;在第一个中找到operator<<()
对StudentInformation<std::string, std::string, int, std::string, std::vector<int>>
的调用,但没有找到实现:链接器错误。
这就是原因,因为它最好在头文件中定义模板类(和相应的模板朋友操作符),而不是在cpp文件中。
奖金错误。
此代码在operator<<()
for( size_t idx = 0; idx < numArgs; idx++ )
out << std::get<idx>( c.members) << " ";
这个代码在operator>>()
for( size_t idx = 0; idx < numArgs; idx++ )
in >> std::get<idx>( c.members);
显然是错误的,因为std::get()
需要,对于模板参数,编译时知道值和idx
,显然,在编译时不知道。