如何显式调用运算符<<的模板重载?

时间:2019-11-08 00:54:04

标签: c++ g++ operator-overloading specifications

考虑以下示例代码,将operator<<重载为class A

#include <iostream>
class A {
    template <typename T>
    friend A &operator<<(A &a, const T &t)
    {
         std::cout << t << std::endl;
         return a;
    }
    friend A &operator<<(A &a, const std::string &t)
    {
         return operator<<<std::string>(a, t + "x");
    }
};

我的意图是第二个运算符显式调用第一个。

但是,在g ++ 7.4中,此操作失败

  

在函数'A&运算符<<(A&,const string&)'中:
  错误:“ operator <<”未定义
  返回运算符<<< std :: string>(a,t +“ x”);
  ^〜
  错误:“>”令牌之前的预期主表达式
  返回运算符<<< std :: string>(a,t +“ x”);
  ^

但是我不明白为什么不应该编译。

Here is the code in godbolt.

3 个答案:

答案 0 :(得分:2)

班级好友功能不会暴露在任何范围内。朋友注入曾经是一回事(在发明ADL之前),但是现在除非使用ADL除非事先声明,否则现在无法调用它们。在这种情况下,一种解决方法是事先在类外部声明模板函数。

class A;

template <typename T>
A &operator<<(A &a, const T &t);

答案 1 :(得分:1)

调用函数而不是调用运算符。

#include <iostream>
class A {
    template <typename T>
    static A &print(A &a, const T &t)
    {
        std::cout << t << std::endl;
        return a;
    }

    template <typename T>
    friend A &operator<<(A &a, const T &t)
    {
         return print(a, t);
    }
    friend A &operator<<(A &a, const std::string &t)
    {
         return print(a, t + "x");
    }
};

答案 2 :(得分:1)

您似乎希望specialize your template function,但您做得不太正确。它应该看起来像这样:

template <> friend A& operator<< <std::string>(A &a, const std::string &t)
{
    // Print in here some how. It's not exactly clear to me how you intend to
    // do this, as doing something like a << t will create infinite recursion

    // finally, return a
    return a;
}

您的另一个选择是切换功能的顺序,在创建第一个功能后创建模板功能

friend A &operator<<(A &a, const std::string &t)
{
    // Again, still not sure what you want to do here
    // I just want to stress again though, don't do something
    // like a << t, or operator<<(a,t)
    // That will crash hard and fast, as there is no way to resolve
    // it. It will create infinite recursion

    return a;
}

template <typename T>
friend A &operator<<(A &a, const T &t)
{
     std::cout << t << std::endl;
     return a;
}
  

我的意图是第二个运算符显式调用第一个。

因此,首先,在这种情况下,您实际上需要第一个选项。

第二,要执行此操作,您将需要为t选择一种类型。您可以这样做:

operator<< <SomeType>(a,t);

请记住,t必须是implicitly convertedSomeType。否则,SomeType需要通过调用其构造函数来创建:

operator<< <SomeType>(a,SomeType(/* parameters to construct a SomeType ... */));

注意:做类似operator<< <SomeType>(a,t + "x")的事情将始终变成infinitely recursive,并最终崩溃。这是因为t + "x"始终是std::string。这意味着编译器将始终无限调用此函数的重载,直到最终从stack overflow崩溃为止。所以不要那样。