【问题标题】:Overloading the << operator in a templated class gives me linker errors (C++) [duplicate]在模板类中重载 << 运算符会给我链接器错误(C++)[重复]
【发布时间】:2015-01-28 04:45:27
【问题描述】:

在你问之前,是的,这个函数是在我的模板类的头文件中定义的。

这是Example.h的相关位:

template<class T, class J, const int X, const int Y>
class Example {
    public:
        friend std::ostream& operator<<(std::ostream& s, const Example<T,J,X,Y>& b);
}

template<class T, class J, const int X, const int Y>
std::ostream& operator<<(std::ostream& s, const Example<T,J,X,Y>& b) {
    // stuff
}

我是从main.cpp打来的:

void foo(Example<A,B,5,5>& b) {
    std::cout << b;
}

int main() {
    Example<A,B,5,5> b = Example<A,B,5,5>();
    foo(b);
}

编译时出现以下链接器错误:

Undefined symbols for architecture x86_64:
  "operator<<(std::__1::basic_ostream<char, std::__1::char_traits<char> >&, Example<A, B, 5, 5> const&)", referenced from:
      foo(Example<A, B, 5, 5>&) in main.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
make[2]: *** [dist/Debug/GNU-MacOSX/consolehero] Error 1
make[1]: *** [.build-conf] Error 2
make: *** [.build-impl] Error 2

【问题讨论】:

    标签: c++ templates linker operator-overloading


    【解决方案1】:

    长话短说:

    warning: friend declaration ‘std::ostream& operator<<
    (std::ostream&, const Example<T, J, X, Y>&)’ declares a non-template function
    

    您的声明没有声明模板函数,因为在实例化时所有类型都是已知的。您稍后将其定义为模板函数,链接器变得非常混乱。最简单的方法是在类内部定义运算符inline,比如

    template<class T, class J, const int X, const int Y>
    class Example {
        public:
            friend std::ostream& operator<<(std::ostream& s, const Example& b)
            { 
                // stuff here
            }
    };
    

    或者,使用

    template<class T, class J, const int X, const int Y>
    class Example {
        public:
            template<class T1, class J1, const int X1, const int Y1>
            friend std::ostream& operator<<(std::ostream& s, 
                                             const Example<T1,J1,X1,Y1>& b);
    };
    
    template<class T1, class J1, const int X1, const int Y1>
    std::ostream& operator<<(std::ostream& s, const Example<T1,J1,X1,Y1>& b) {
        // stuff
    }
    

    我发现第一种方法更有吸引力。请注意,这两种方法并不等效。在第一种情况下,每次实例化都会生成一个非模板operator&lt;&lt;,而在第二种情况下,operator&lt;&lt; 是模板化的,因此只有在使用其友元类的类型显式调用它时才会生成它,通过类型推导。这是一个相当微妙的观点,我真的不知道什么时候人们会更喜欢第二种方法而不是第一种方法。

    PS:对于第一种方法,请参阅http://en.cppreference.com/w/cpp/language/friend 模板友元运算符,以获得更多说明。引用它:

    这样的操作符可以在类体中定义,它的作用是为每个T生成一个单独的非模板操作符

    所以,本质上是一个类内定义

    friend std::ostream& operator<<(std::ostream& s, const Example& b){}
    

    等价于

    friend std::ostream& operator<<(std::ostream& s, const Example<T,J,X,Y>& b){}
    

    【讨论】:

    • 伙计,这东西令人困惑。我通过删除类中的定义来使其工作。然后我在定义中添加了inline。它有效 - 但如何?在 Example 上调用 &lt;&lt; 运算符时,程序如何知道使用 THAT 函数?
    • @maxmackie 找到了一些文档,查看更新后的编辑或en.cppreference.com/w/cpp/language/friend(模板好友操作员)
    猜你喜欢
    • 2012-11-14
    • 1970-01-01
    • 2023-03-11
    • 2021-09-19
    • 2013-03-05
    • 2016-06-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多