C++ 可变参数模板和隐式转换

6

我试图研究C++编译器在可变模板构造函数和转换运算符同时存在时如何解决隐式转换。以下是一个最小化的示例:

当我写下:

#include <iostream>

class A {
public:
    A () {}

    template<typename...tTypes> A (tTypes...pArgs) {
        std::cout << __PRETTY_FUNCTION__ << std::endl;
    }
};

class B {
public:
    operator A () const {
        std::cout << __PRETTY_FUNCTION__ << std::endl;
        return A();
    }
};

int main() {
    B b;
    A a = b;
}

运行时,我得到了这个输出:B::operator A() const。所以它使用了转换运算符(正如我所预期的)。实时示例在http://ideone.com/ZZ2uBz
但当A是一个模板时,结果会有所不同:
#include <iostream>

template<typename tType>
class A {
public:
    A () {}

    template<typename...tTypes> A (tTypes...pArgs) {
        std::cout << __PRETTY_FUNCTION__ << std::endl;
    }
};

class B {
public:
    template<typename tType>
    operator A<tType> () const {
        std::cout << __PRETTY_FUNCTION__ << std::endl;
        return A<tType>();
    }
};

int main() {
    B b;
    A<float> a = b;
}

运行此程序时,我得到了这个输出:A<tType>::A(tTypes ...) [with tTypes = {B}; tType = float]。因此,它使用了A的可变参数构造函数,而不是B中的转换运算符。在http://ideone.com/u9Rxuh上有实时示例。
有人能解释一下为什么会有这种差异吗?转换运算符难道不应该比构造函数优先吗?
我知道我可以显式调用转换运算符(A<float> a = b.operator A<float>();),但那不是我想要的。

1
我怀疑转换是有歧义的。实际上,clang 拒绝它。可能是GCC的一个错误(?)。 - skypjack
你是正确的,其他编译器认为这种转换是不明确的(在我看来,这比任意选择要好得多)。您知道有没有一种方法可以在不使用显式转换的情况下消除歧义吗? - Lagf
1
使用显式构造函数(explicit constructor)替代。我会将这个信息放在一个回答里面,稍等几分钟。 - skypjack
1个回答

2

在我看来,转换是模糊的,其他编译器无法按预期运行(或者至少,这是我的期望)。例如,查看使用clang的结果。

为了消除歧义,您可以使构造函数或转换运算符显式。
例如,使用以下内容:

template<typename tType>
class A {
public:
    A () {}

    template<typename...tTypes> explicit A (tTypes...pArgs) { /* ... */ }
};

或者这样:
class B {
public:
    template<typename tType>
    explicit operator A<tType> () const { return A<tType>(); }
};

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接