正在编译和评估 conditional_t 中的错误大小写问题
Problem with false case in conditional_t being compiled and evaluated
我很难理解如何在 false 分支中使用 std::conditional_t
阻止代码被计算。
#include <type_traits>
using namespace std;
namespace {
template <typename T>
using BaseDifferenceType = decltype (T{} - T{});
}
int main ()
{
using T = int;
static_assert(! is_enum_v<T>);
BaseDifferenceType<T> xxx {};
// PROBLEM IS HERE - though is_enum is false, we still evaluate underlying_type<T> and complain it fails
using aaa = conditional_t<is_enum_v<T>, underlying_type_t<T>, BaseDifferenceType<T>>;
return 0;
}
您可以在 https://www.onlinegdb.com/uxlpSWVXr 在线试用。
编译(使用 C++17)给出错误:
error: ‘int’ is not an enumeration type
typedef __underlying_type(_Tp) type;
^~~~ main.cpp: In function ‘int main()’: main.cpp:16:87: error: template argument 2 is invalid
using aaa = conditional_t<is_enum_v<T>, underlying_type_t<T>, BaseDifferenceType<T>>;
答案很简单:
你没有。
std::conditional_t
始终具有三个 完全评估的 个参数:
类似布尔值的东西,和两种类型。
如果选择其中一个无法评估另一个,则需要使用自定义模板并对其进行适当的专门化:
template <class T, bool = std::is_enum_v<T>>
struct type_finder { using type = std::underlying_type_t<T>; };
template <class T>
struct type_finder<T, false> { using type = BaseDifferenceType<T>; };
template <class T>
using type_finder_t = typename type_finder<T>::type;
另一种方法是使用 if constexpr
和自动 return-type-deduction:
template <class T>
auto type_finder_f() {
if constexpr (std::is_enum_v<T>)
return std::underlying_type_t<T>();
else
return BaseDifferenceType<T>();
}
template <class T>
using type_finder_t = decltype(type_finder_f<T>());
一种可能的替代方法是通过创建自定义类型特征,如下所示
template <template <typename...> class Cont, typename ... Ts>
struct LazyType
{ using type = Cont<Ts...>; };
并重写你的 std::conditional
如下
using aaa = std::conditional_t<
std::is_enum_v<T>,
LazyType<underlying_type_t, T>,
LazyType<BaseDifferenceType, T>>::type;
// ............................................^^^^^^
注意我添加了一个final ::type
:它是所需类型的“构造函数”,完全避免了不需要的类型。
题外话不请自来的建议:避免
using namespace std;
是considered bad practice
我很难理解如何在 false 分支中使用 std::conditional_t
阻止代码被计算。
#include <type_traits>
using namespace std;
namespace {
template <typename T>
using BaseDifferenceType = decltype (T{} - T{});
}
int main ()
{
using T = int;
static_assert(! is_enum_v<T>);
BaseDifferenceType<T> xxx {};
// PROBLEM IS HERE - though is_enum is false, we still evaluate underlying_type<T> and complain it fails
using aaa = conditional_t<is_enum_v<T>, underlying_type_t<T>, BaseDifferenceType<T>>;
return 0;
}
您可以在 https://www.onlinegdb.com/uxlpSWVXr 在线试用。
编译(使用 C++17)给出错误:
error: ‘int’ is not an enumeration type
typedef __underlying_type(_Tp) type;
^~~~ main.cpp: In function ‘int main()’: main.cpp:16:87: error: template argument 2 is invalid
using aaa = conditional_t<is_enum_v<T>, underlying_type_t<T>, BaseDifferenceType<T>>;
答案很简单:
你没有。
std::conditional_t
始终具有三个 完全评估的 个参数:
类似布尔值的东西,和两种类型。
如果选择其中一个无法评估另一个,则需要使用自定义模板并对其进行适当的专门化:
template <class T, bool = std::is_enum_v<T>>
struct type_finder { using type = std::underlying_type_t<T>; };
template <class T>
struct type_finder<T, false> { using type = BaseDifferenceType<T>; };
template <class T>
using type_finder_t = typename type_finder<T>::type;
另一种方法是使用 if constexpr
和自动 return-type-deduction:
template <class T>
auto type_finder_f() {
if constexpr (std::is_enum_v<T>)
return std::underlying_type_t<T>();
else
return BaseDifferenceType<T>();
}
template <class T>
using type_finder_t = decltype(type_finder_f<T>());
一种可能的替代方法是通过创建自定义类型特征,如下所示
template <template <typename...> class Cont, typename ... Ts>
struct LazyType
{ using type = Cont<Ts...>; };
并重写你的 std::conditional
如下
using aaa = std::conditional_t<
std::is_enum_v<T>,
LazyType<underlying_type_t, T>,
LazyType<BaseDifferenceType, T>>::type;
// ............................................^^^^^^
注意我添加了一个final ::type
:它是所需类型的“构造函数”,完全避免了不需要的类型。
题外话不请自来的建议:避免
using namespace std;
是considered bad practice