【问题标题】:Priority and ambiguity of explicit conversion operator templates显式转换运算符模板的优先级和歧义
【发布时间】:2018-04-07 01:55:34
【问题描述】:

我一直在我的项目中使用模板显式转换运算符,以实现从自定义变体类型的显式转换。重现我的问题的最小示例如下所示(在 C++14 模式下):

#include <iostream>
#include <stdexcept>
#include <cmath>

using namespace std;

class A
{
        public:
        template<typename T> explicit operator T() const // 1
        {
                cout << "operator T" << endl;
                return T();
        }

        template<typename T> explicit operator const T&() const // 2
        {
                cout << "operator const T&" << endl;
                throw runtime_error("operator const T&");
        }

        template<typename T> explicit operator T&() // 3
        {
                cout << "operator T&" << endl;
                throw runtime_error("operator T&");
        }


};


int main(int, char**)
{
        try
        {
                const A& a = A();
                cout << abs(static_cast<double>(a) - 3.14) << endl;
        }
        catch (const runtime_error&)
        {

        }

        return 0;
}

我面临的问题是为 static_cast 转换选择的运算符。对于 GCC,这是一种预期的 (1) 案例。输出是:

operator T
3.14

但 Clang 拒绝使用以下输出编译它:

main.cpp:37:20: error: ambiguous conversion for static_cast from 'const A' to 'double'
            cout << std::abs(static_cast<double>(a) - 3.14) << endl;
                             ^~~~~~~~~~~~~~~~~~~~~~
main.cpp:10:32: note: candidate function [with T = double]
    template<typename T> explicit operator T() const
                                  ^
main.cpp:16:32: note: candidate function [with T = double]
    template<typename T> explicit operator const T&() const
                                  ^
1 error generated.

为什么 Clang 考虑转换 (2),而它显然需要在转换序列中调用额外的构造函数,而 (1) 则不需要?这样做是正确的(而 GCC 是错误的)吗?

【问题讨论】:

  • 但是你为什么要这样做呢?同时拥有operator T()operator const T&amp; 有什么意义?
  • @ArneVogel 在实际代码中它的目的是提供替代转换序列,例如,如果变体持有long double,那么operator T() 将有助于将其转换为int。但显然我误解了static_cast 实际执行的事情,所以这种转换为价值确实是多余的。

标签: c++ c++11 templates overload-resolution explicit-conversion


【解决方案1】:

static_cast 执行隐式转换或直接初始化。在您的情况下,隐式转换不可行,但直接初始化,因为static_cast 考虑explicit constructors and conversion functions。所以我的猜测是clang(在我看来是正确的)识别出有两种可能的直接初始化并相应地抱怨。不知道 GCC 内部发生了什么,也许它默认为operator T(),如果它可以找到一个,不管是否存在其他的。

【讨论】:

  • 是的,我倾向于同意。显然static_cast 没有按原样执行显式用户定义的转换,没有直接初始化new-type,对于这个初始化operator Toperator const T&amp; 看起来都合适。感谢您指出这一点。仍然不太清楚,如何选择合适的用户定义转换。如果转换过程是隐式转换,但也考虑到定义的显式转换,那么解析是基于复制构造的可能性,是的,这两个运算符同样适用。
猜你喜欢
  • 2021-01-01
  • 1970-01-01
  • 2017-07-04
  • 2012-05-04
  • 2017-04-14
  • 2016-02-19
  • 1970-01-01
  • 1970-01-01
  • 2019-05-15
相关资源
最近更新 更多