我目前正在与Visual Studio 2017进行斗争(如果有任何帮助,请使用/std:c++latest
进行编译)。
有问题的代码只是根据某个模板constexpr
函数的结果选择结构专门化。 GCC和clang编译它没有任何问题。
这是我的MCVE:
#include <type_traits>
struct A {
enum {
test_trait = true
};
};
template<typename T>
constexpr int choose() {
return T::test_trait;
}
template<typename T, typename Enable=void>
struct Chosen;
template<typename T>
struct Chosen<T, std::enable_if_t<choose<T>() == 1>> {};
void foo() {
// This works
constexpr int chosen = choose<A>();
static_assert(chosen == 1, "");
// This resolves to the undefined struct.
using Chosen_t = Chosen<A>;
Chosen_t x;
(void)x;
}
在我的代码库中, choose()
实际上要复杂得多,但static_assert
仍在编译,并且检查正常。
我有点假设如果static_assert
编译,enable_if
没有理由不能发挥它的魔力。我错了吗?我猜“也许”T
在技术上并不是enable_if
的依赖类型......但如果是这样的话,我会期待GCC和clang打我的手腕。
我可以通过将choose()
的结果包装在std::integral_constant
中来解决这个问题,如下所示:
template<typename T>
struct Chooser : public std::integral_constant<int, choose<T>()> {};
template<typename T>
struct Chosen<T, std::enable_if_t<Chooser<T>::value>> {};
但我真的不必跳过那个圈子。
模板解析能否以我期望的方式解决这个问题?我担心代码实际上是错的,GCC和clang对我很宽容。
答案 0 :(得分:0)
在MSVC 19.00.23506中,代码似乎仍然被破坏。但是,它似乎只使用了一个间接级别(可能是更好的解决方法):
template<typename T, bool>
struct ChosenImpl;
template<typename T>
struct ChosenImpl<T, true> {};
template<typename T>
using Chosen = ChosenImpl<T, choose<T>()>;
这样做的好处是我们隐藏了来自呼叫者的第二个模板参数,无论如何他们都不关心。