当我更改类型参数名称时,模板替换失败 - 编译器错误?

时间:2016-08-16 21:29:11

标签: c++ visual-studio templates template-meta-programming compiler-bug

以下大部分代码均来自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 ++标准中的一些奇怪的行为;解决方法非常简单。

1 个答案:

答案 0 :(得分:2)

表达sfinae在msvc 2015中不起作用。任何有效的情况都是偶然的,不要相信它。 decltype 不能用于在msvc 2015中可靠地导致sfinae

停下来,走开,找到另一种解决方案。也许尝试编译器内在函数。

当参数名称匹配时,不要假设意外工作意味着其他任何东西都可以工作,或者它可以在稍微不同的程序中工作。

您的解决方法无法信任。