所以我把它归结为最小的,完整的,可验证的示例,看起来Visual Studio 2015似乎不允许我在{{{{{}}中使用模板化的constexpr
函数1}}。
例如:
enable_if
给我错误:
错误C2995:
template <typename T> constexpr bool condition() { return sizeof(T) > 1; }
:功能模板已定义
当我尝试在替换中使用它时,失败不是像这样的错误编译:
enable_if<_Test,T>::type test(void)
这在gcc中运行良好:http://ideone.com/m9LDdS
如果我删除了template <typename T>
enable_if_t<condition<T>()> test() { cout << "true\n"; }
template <typename T>
enable_if_t<!condition<T>()> test() { cout << "false\n"; }
的模板化,它在Visual Studio 2015中运行良好。我相信在c++11中引入了condition
函数,为什么Visual Studio 2015不支持此功能?这是一个错误吗?
答案 0 :(得分:6)
问题似乎是MSVC14 / VS2015无法正确解析SFINAE表达式并结合constexpr函数的返回值作为模板参数。
作为一种解决方法,您可以将constexpr的返回值分配给一个“静态常量”&#39;结构的成员,并使用此成员作为模板参数。
#include <type_traits>
#include <iostream>
using std::enable_if_t;
using std::cout;
template <typename T>
constexpr bool condition() { return sizeof(T) > 1; }
template <typename T>
struct condition_ { static const bool value = condition<T>();};
template <typename T>
enable_if_t<condition_<T>::value> test() { cout << "true\n"; }
template <typename T>
enable_if_t<!condition_<T>::value> test() { cout << "false\n"; }
int main() {
test<int>();
test<bool>();
return 0;
}
http://rextester.com/VVNHB62598
您还在评论中提到,您的实际问题出现在另一个案例中而不是您的MCVE(How can I Initialize a div_t Object?)
对于这种情况,解决方法可能如下所示:
#include <type_traits>
#include <cstdlib>
#include <utility>
template <typename T>
using divtype = decltype(std::div(std::declval<T>(), std::declval<T>()));
template <typename T>
struct condition
{
static const bool value = divtype<T>{ 1, 0 }.quot != 0;
};
template <typename T>
std::enable_if_t<condition<T>::value, divtype<T>> make_div(const T quot, const T rem) { return{ quot, rem }; }
template <typename T>
std::enable_if_t<!condition<T>::value, divtype<T>> make_div(const T quot, const T rem) { return{ rem, quot }; }
int main() {
make_div<int>(1, 2);
return 0;
}
http://rextester.com/ULDFM22040
根据此Visual Studio C++ Team blog entry,VS2015还没有(完全)支持Expression SFINAE。
[1]我们计划在2015 RTM之后立即开始在编译器中实现Expression SFINAE,并且我们计划在2015年更新中提供它,支持生产使用。 (但不一定是2015年更新1.可能需要更长时间。)
答案 1 :(得分:3)
问题是您最终得到了两种形式的test
模板:
template<class>void test()
并且编译器抱怨。这可能与表达SFINAE失败有关,它不能及早评估condition<T>()
的表达,或以其他方式失败。
这是一种解决方法:
template<std::size_t>
struct counter{ enum type{}; };
template<std::size_t N>
using counter_type=typename counter<N>::type;
template <typename T>
constexpr bool condition() { return sizeof(T) > 1; }
template <class T,counter_type<0>...,class=std::enable_if_t<condition<T>()>>
void test() { std::cout << "true\n"; }
template <class T,counter_type<1>...,class=std::enable_if_t<!condition<T>()>>
void test() { std::cout << "false\n"; }
现在两个不同的test
的模板签名不同,而condition<T>()
的{{1}}表达式的表达式不正确也不会导致问题。
答案 2 :(得分:2)
@ Yakk回答的另一个选择:
template <class T, std::enable_if_t<(sizeof(T) > 1)>* = nullptr>
void test() { std::cout << "true\n"; }
template <class T, std::enable_if_t<!(sizeof(T) > 1)>* = nullptr>
void test() { std::cout << "false\n"; }
编辑:刚看到这基本上是TC在评论中指出的解决方案。
EDIT2:更正了在MSVC2015中编译的代码,请参阅注释。
答案 3 :(得分:1)
这是一个已知的MSVC问题,并在其中一篇博文中提到过。发生了什么事情,编译器无法识别SFINAE使第二版test()
与第一版不同,需要一点提示;一个简单的虚拟参数就足够了,可以区分这两个版本。
#include <type_traits>
#include <iostream>
using std::enable_if_t; using std::cout;
template <typename T>
constexpr bool condition() { return sizeof(T) > 1; }
#ifdef _MSC_VER
#define MSVC_DUMMY int /*msvc_dummy*/ = 0
#else // _MSC_VER
#define MSVC_DUMMY
#endif // _MSC_VER
template <typename T>
enable_if_t<condition<T>()> test() { cout << "true\n"; }
template <typename T>
enable_if_t<!condition<T>()> test(MSVC_DUMMY) { cout << "false\n"; }
int main() {
test<char>();
test<int>();
}
这个works on MSVC,对代码的修改很少。一旦它们最终在没有提示的情况下工作,它也很容易被移除。
如果需要一致的界面,可以隐藏在辅助函数后面。
template <typename T>
enable_if_t<condition<T>()> test_() { cout << "true\n"; }
template <typename T>
enable_if_t<!condition<T>()> test_(MSVC_DUMMY) { cout << "false\n"; }
template <typename T>
auto test() { return test_<T>(); }