Gui*_*cot 6 c++ templates conversion-operator language-lawyer
我不得不做类似的代码:
#include <type_traits>
template<typename S>
struct probe {
template<typename T, typename U = S, std::enable_if_t<
std::is_same<T&, U>::value &&
!std::is_const<T>::value, int> = 0>
operator T& () const;
template<typename T, typename U = S&&, std::enable_if_t<
std::is_same<T&&, U>::value &&
!std::is_const<T>::value, int> = 0>
operator T&& ();
template<typename T, typename U = S, std::enable_if_t<
std::is_same<T const&, U>::value, int> = 0>
operator T const& () const;
template<typename T, typename U = S&&, std::enable_if_t<
std::is_same<T const&&, U>::value, int> = 0>
operator T const&& () const;
};
struct some_type {};
struct other_type {};
auto test_call(some_type const&, other_type) -> std::false_type;
auto test_call(some_type&, other_type) -> std::true_type;
int main() {
static_assert(decltype(test_call(probe<some_type&>{}, other_type{}))::value, "");
}
Run Code Online (Sandbox Code Playgroud)
它在GCC和Clang下工作,但它不能在visual studio上编译,并且有一个模糊的分辨率错误.哪个编译器错了,为什么?
这是msvc输出:
Run Code Online (Sandbox Code Playgroud)source_file.cpp(31): error C2668: 'test_call': ambiguous call to overloaded function source_file.cpp(28): note: could be 'std::true_type test_call(some_type &,other_type)' source_file.cpp(27): note: or 'std::false_type test_call(const some_type &,other_type)' source_file.cpp(31): note: while trying to match the argument list '(probe<some_type &>, other_type)' source_file.cpp(31): error C2651: 'unknown-type': left of '::' must be a class, struct or union source_file.cpp(31): error C2062: type 'unknown-type' unexpected
代码可以简化为以下内容:
#include <type_traits>
struct some_type {};
struct probe {
template<typename T, std::enable_if_t<!std::is_const<T>::value, int> = 0>
operator T& () const;
};
auto test_call(some_type const&) -> std::false_type;
auto test_call(some_type&) -> std::true_type;
int main() {
static_assert(decltype(test_call(probe{}))::value, "");
}
Run Code Online (Sandbox Code Playgroud)
一般来说,推导过程会尝试找到使推导的 A 与 A 相同的模板参数值。但是,有四种情况允许存在差异:
如果原始 A 是引用类型,则 A 可以比推导的 A 更具 cv 限定性(即引用引用的类型)
...
仅当类型推导失败时才考虑这些替代方案。如果它们产生多个可能的推导 A,则类型推导失败。
T推断适用some_type于两个函数调用。然后根据 [over.ics.rank]/ 3.3:
如果用户定义的转换序列 U1 包含相同的用户定义的转换函数或构造函数,或者它们在聚合初始化中初始化相同的类,并且在任一情况下都是第二个标准转换序列,则用户定义的转换序列 U1 是比另一个用户定义的转换序列 U2 更好的转换序列U1的第二标准转换序列优于U2的第二标准转换序列。
probe -> some_type& -> some_type&比 更好probe -> some_type& -> const some_type&,所以没有歧义,GCC 和 Clang 是正确的。
顺便说一句,如果我们删除std::enable_if_t<...>上面代码中的一部分,MSVC 和 GCC 在 Clang 编译时会失败。为了进一步分析,我重点关注第一个test_all:
#include <type_traits>
struct some_type {};
struct probe {
template<typename T>
operator T& () const
{
static_assert(std::is_const_v<T>);
static T t;
return t;
}
};
auto test_call(some_type const&) -> std::false_type;
int main() {
test_call(probe{});
}
Run Code Online (Sandbox Code Playgroud)
然后我们发现static_assert火只在 Clang 下。也就是说,Clang 推导T为 besome_type而不是const some_type。我认为这是 Clang 的一个错误。
| 归档时间: |
|
| 查看次数: |
136 次 |
| 最近记录: |