在可变参数模板中重载朋友ostream操作符[重复]

问题描述 投票:0回答:1

这个问题在这里已有答案:

我正在尝试将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
operator-overloading variadic-templates iostream c++17 friend
1个回答
0
投票

这是经典之作。

当你编译main()(比如在“main.cpp”中)时,你有

std::cout << studentA << '\n';

其中studentAStudentInformation<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,显然,在编译时不知道。

© www.soinside.com 2019 - 2024. All rights reserved.