c++ - 隐式转换运算符 vs 模板构造函数——应该优先考虑谁?

标签 c++ language-lawyer c++17 copy-elision conversion-operator

考虑以下代码片段:

template <typename>
struct dependent_false { static constexpr auto value = false; };

struct foo
{
    foo() { }

    template <typename T>
    foo(const T&) { static_assert(dependent_false<T>::value, ""); }
};

struct proxy
{
    operator foo() { return foo{};  }
};

int main()
{
    (void) foo{proxy{}};
}

使用 -std=c++17 编译时:

  • clang++ (trunk)成功编译代码;

  • g++ (trunk) 编译代码失败 - 它实例化 foo(const T&)

使用 -std=c++11 编译时,两个编译器都拒绝该代码。 C++17 中新的 prvalue 物化规则可能会影响此处的行为。

live example on godbolt.org


这里的正确行为是什么?

  • 标准是否保证 foo::foo(const T&) 将被(或不被)实例化?

  • 标准是否保证隐式转换运算符优先于 foo::foo(const T&) 的调用,无论是否它被实例化了吗?

最佳答案

这是 CWG 2327 :

Consider an example like:

struct Cat {};
struct Dog { operator Cat(); };

Dog d;
Cat c(d);

This goes to 11.6 [dcl.init] bullet 17.6.2:

Otherwise, if the initialization is direct-initialization, or if it is copy-initialization where the cv-unqualified version of the source type is the same class as, or a derived class of, the class of the destination, constructors are considered. The applicable constructors are enumerated (16.3.1.3 [over.match.ctor]), and the best one is chosen through overload resolution (16.3 [over.match]). The constructor so selected is called to initialize the object, with the initializer expression or expression-list as its argument(s). If no constructor applies, or the overload resolution is ambiguous, the initialization is ill-formed.

重载决议选择Cat的移动构造函数。根据 11.6.3 [dcl.init.ref] 项目符号 5.2.1.2,初始化构造函数的 Cat&& 参数会导致临时。这排除了这种情况下复制省略的可能性。

这似乎是对保证复制省略的措辞更改的疏忽。在这种情况下,我们大概应该同时考虑构造函数和转换函数,就像我们对复制初始化所做的那样,但我们需要确保这不会引入任何新问题或歧义。

我相信 clang 实现了这个隐含的变化(因此认为转换函数更匹配)而 gcc 没有(因此从未真正考虑过转换函数)。

根据标准,gcc 是正确的。

关于c++ - 隐式转换运算符 vs 模板构造函数——应该优先考虑谁?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50821676/

相关文章:

c++ - 为什么 (int&)0 格式不正确?

c++ - 访问者访问变体并返回不同类型时出错

c++ - 具有不同参数顺序的聚合初始化

c++ - 指向 boost 共享指针 vector 的空指针

c++ - vector<string> 可以容纳多少数据?

javascript - 论点在词汇环境中的位置在哪里?

c++ - 不明确的成员访问表达式 : is Clang rejecting valid code?

c++ - 在并行算法中使用 ranges::view::iota

c++ - 在二叉搜索树 C++ 中插入字符串时出错

c++ - 如何使虚函数接受仅在派生类中定义的数据类型?