以下大部分代码均来自Piotr Skotnicki的answer。我正在试验它并发现了我认为是MSVC 14.0 Update 3中的一个错误。
请考虑以下代码:
Collection
这会按预期打印#include <iostream>
template <typename T>
struct identity { using type = T; };
template <typename...>
using void_t = void;
template <typename F>
struct call_operator;
template <typename C, typename R, typename... A>
struct call_operator<R(C::*)(A...)> : identity<R(A...)> {};
template <typename C, typename R, typename... A>
struct call_operator<R(C::*)(A...) const> : identity<R(A...)> {};
template <typename F>
using call_operator_t = typename call_operator<F>::type;
template <typename, typename = void_t<>>
struct is_convertible_to_function
: std::false_type {};
template <typename L>
struct is_convertible_to_function<L, void_t<decltype(&L::operator())>>
: std::is_assignable<call_operator_t<decltype(&L::operator())>*&, L> {};
template <typename, typename = void_t<>>
struct is_callable_object
: std::false_type {};
template <typename L>
struct is_callable_object<L, void_t<decltype(&L::operator())>>
: std::true_type {};
int main()
{
auto x = []() {};
std::cout << std::boolalpha << is_callable_object<decltype(x)>::value;
std::getchar();
}
,因为编译器生成的lambda对象确实实现了true
。
现在让我们将operator()
中的类型参数名称从is_callable_object
更改为L
(与T
中使用的类型名称不同导致此问题,从我看到的)。
is_convertible_to_function
突然,会打印template <typename, typename = void_t<>>
struct is_callable_object
: std::false_type {};
template <typename T>
struct is_callable_object<T, void_t<decltype(&T::operator())>>
: std::true_type {};
。 false
应该无关紧要,因为is_convertible_to_funtion
不以任何方式依赖它;实际上,如果我删除is_callable_object
,这个问题就会消失 - 我可以使用我想要的任何类型名称。
正如我所说,我怀疑这是一个错误,所以我问这个问题,以确保这不是C ++标准中的一些奇怪的行为;解决方法非常简单。
答案 0 :(得分:2)
表达sfinae在msvc 2015中不起作用。任何有效的情况都是偶然的,不要相信它。 decltype
不能用于在msvc 2015中可靠地导致sfinae 。
停下来,走开,找到另一种解决方案。也许尝试编译器内在函数。
当参数名称匹配时,不要假设意外工作意味着其他任何东西都可以工作,或者它可以在稍微不同的程序中工作。
您的解决方法无法信任。