以下代码大部分摘自Piotr Skotnicki的answer。我用它进行试验,发现了我认为是MSVC 14.0更新错误3.当我更改类型参数名称时,模板替换失败 - 编译器错误?
考虑下面的代码:
#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();
}
这将打印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
不以任何方式依赖它;的确,如果我删除is_convertible_to_function
,这个问题就会消失 - 我可以使用任何我想要的类型名称。正如我所说,我怀疑这是一个错误,所以我问这个问题,以确保这不是在C++标准中的一些奇怪的行为;解决这个问题的办法很简单。
我想知道您的声明是不是太过分极端,但即使是微软自己也承认:https://blogs.msdn.microsoft.com/vcblog/2015/12/02/partial-support-for-表达-SFINAE-在-VS-2015-更新-1 /。哦,我会继续试验,谢谢。 – szczurcio