【问题标题】:Overloading operator outside template struct在模板结构外重载运算符
【发布时间】:2012-10-15 16:51:26
【问题描述】:

我有以下代码:

#include <iostream>
#include <stdio.h>
using namespace std;

template <class F>
struct CMPLX {

    F Re, Im;

    struct _printnice {
        F Re, Im;
        string sep;
        _printnice(const F& Re, const F& Im, const string& sep) : Re(Re), Im(Im), sep(sep) {}
    };

    CMPLX <F> (F Re, F Im) : Re(Re), Im(Im) {}

    _printnice PrintNice(const string& sep="\t"){
        return _printnice(Re, Im, sep);
    }

};

template<class F>
ostream& operator << (ostream& os, const CMPLX<F> c){
    cout << c.Re << " + " << c.Im << "i";
}

template<class F>
ostream& operator << (ostream& os, const CMPLX<F> :: _printnice p){
    cout << p.Re << p.sep << p.Im;
}

int main(){
    CMPLX<float> c(2.0,1.0);
    cout << c << endl;
    cout << c.PrintNice() << endl;

}

我引入了一个子结构 _printnice 以重载运算符 &lt;&lt; 并具有我的 CMPLX 类的不同格式的输出。但是,这会引发错误 在“p”之前应该是 unqualified-id,我不知道如何解决这个问题(我对模板的了解非常有限)。

我尝试将&lt;&lt; 的第二个定义更改为以下有效,但我必须指定类型,这是不受欢迎的:

ostream& operator << (ostream& os, const CMPLX <float> :: _printnice p){
    cout << p.Re << p.sep << p.Im;
}

【问题讨论】:

    标签: c++ function templates


    【解决方案1】:

    您的方法存在两个问题。首先是_printnice 是一个从属名称,因此您需要添加一个额外的typename。如果解决了这个问题,你最终会得到:

    template<class F>
    ostream& operator << (ostream& os, typename CMPLX<F>::_printnice const & p)
    

    正如 Dietmar 在之前的回答中指出的那样,这段代码的问题在于 F 处于不可推断的上下文中,这将失败。

    一个简单的解决方案是在_printnice 代码的范围内定义运算符,其中typename:

    template <class F>
    struct CMPLX {
       //...
       struct _printnice {
          friend std::ostream& operator<<( std::ostream& o, _printnice const & p ) {
             // print here
             return o;
          }
       }
       //...
    };
    

    _printnice 的定义中,类型已知为类型,因此不再需要typename。重载的operator&lt;&lt; 将由 Argument Dependent Lookup 找到,并且因为它引用了该类型的特定实例化,所以没有要推导的模板参数。

    【讨论】:

    • 是的,这样它就可以推断为不再使用限定 ID 指定的嵌套名称说明符,这很棒。唯一的问题是 OP 要求这是“模板结构之外”...
    • @Gob00st 我不认为我要求它在外面,如果你有这种印象,我很抱歉。感谢大卫,这行得通!我不知道你可以完全定义一个friend函数,我一直用它只是在内部声明它并在外部定义它。
    • @Gob00st:在修改后的情况下,没有要推导的模板参数(即它不能被推导,因为没有可推导的参数)。编译器将为每个使用_printnice 嵌套类型的X 类型生成一个非模板化std::ostream&amp; operator&lt;&lt;(std::ostream&amp;,CMPLX&lt;X&gt;::_printnice const&amp;)。我找不到 OP 要求“外部模板结构”的位置......无论如何,在模板结构之外这是不可能的。
    • @both:对不起,我想我在这里弄错了。+1
    【解决方案2】:

    在函数中:

    template <typename F>
    std::ostream& operator<<( std::ostream& os, CMPLX<F>::_printnice p);
    

    F 不在可演绎的上下文中。 (见§14.8.2.5。)

    【讨论】:

    • 来自 c++ 11 标准 :: 使用限定 ID 指定的类型的嵌套名称说明符。
    【解决方案3】:

    注意。这不是一个答案。大卫已经回答了。 FWIW,只是修复了一些问题,以便它可以在 gcc 4.72 下编译和运行。

    #include <iostream>
    #include <stdio.h>
    using namespace std;
    
    template <class F>
    struct CMPLX {
    
        F Re, Im;
    
        struct _printnice {
    
            F Re, Im;
            string sep;
            _printnice(const F& Re, const F& Im, const string& sep) : Re(Re), Im(Im), sep(sep) {}
    
            friend ostream& operator << (ostream& os, const _printnice& p){
                cout << p.Re << p.sep << p.Im;
                return os;
            }
        };
    
        CMPLX <F> (F Re, F Im) : Re(Re), Im(Im) {}
    
        _printnice PrintNice(const string& sep="\t"){
            return _printnice(Re, Im, sep);
        }
    
    };
    
    template<class F>
    ostream& operator << (ostream& os, const CMPLX<F> c){
        cout << c.Re << " + " << c.Im << "i";
        return os;
    }
    
    int main() {
        CMPLX<float> c(2.0,1.0);
        cout << c << endl;
        cout << c.PrintNice() << endl;
    }
    
    //result
    /*
    2 + 1i
    2       1
    */
    

    【讨论】:

    • 使用其他答案后的原始代码在gcc 4.4.5中运行完美,那有什么意义呢?
    • @tohec:怎么就完美了?对于初学者来说,两个运算符
    猜你喜欢
    • 2020-06-25
    • 1970-01-01
    • 2012-11-26
    • 1970-01-01
    • 2015-09-15
    • 1970-01-01
    • 1970-01-01
    • 2022-10-01
    • 2016-04-04
    相关资源
    最近更新 更多