【发布时间】:2019-01-29 01:29:32
【问题描述】:
在对为什么我的代码在 GCC 上给我一个模棱两可的错误而在 Clang 上没有错误感到困惑之后,我简化了代码。如下图所示。
struct Foo
{
// Foo(Foo&&) = delete;
// Foo(const Foo&) = delete;
Foo(int*) {}
};
struct Bar
{
template<typename T>
operator T()
{
return Foo{nullptr};
}
};
int main() { Foo f{Bar{}}; }
错误如下。
main.cpp:17:18: error: call to constructor of 'Foo' is ambiguous
int main() { Foo f{Bar{}}; }
^~~~~~~~
main.cpp:1:8: note: candidate is the implicit move constructor
struct Foo
^
main.cpp:1:8: note: candidate is the implicit copy constructor
main.cpp:5:1: note: candidate constructor
Foo(int*) {}
^
这次我无法为 Clang 成功编译,所以我想这只是一个 Clang 错误,这是预期的行为。
当我显式删除复制和移动构造函数(即取消注释前两行代码)时,我改为得到
note: candidate constructor has been explicitly deleted
但仍然是一个错误。那么,我将如何消除这里的构造歧义呢?
请注意,我专门添加了Foo{nullptr} 而不仅仅是nullptr,但没有区别。与显式标记 Foo ctor 相同。仅当 Bar 的转换运算符被模板化时,才会出现此歧义错误。
我可以向转换运算符添加一些 SFINAE,但我不确定我会排除什么。例如,这将使它工作:
template<typename T, std::enable_if_t<std::is_same<T, Foo>{}>* = nullptr>
这是我找到的另一个,这可能是我的答案:
template<typename T, std::enable_if_t<!std::is_same<T, int*>{}>* = nullptr>
【问题讨论】:
-
为什么转换运算符需要是模板?为什么不只是
operator Foo()? -
@Justin,因为它是一个插图(MCVE)而不是实际问题?
-
因为
Foo不是我将其投射到的唯一类型。这个模板化的转换运算符提供了非常好的语义(参见 nlohmann/json)。 -
在这个例子中你真正希望被称为什么?您的 Bar 可以同时转换为...
标签: c++ templates type-conversion ambiguous