使用 std::conditional 和 is_class<int>,出现编译错误
Using std::conditional with is_class<int>, getting compile error
我想要一个类型,它依赖于具有 X::value_type 的其他 class X。
如果另一个 class 中没有这样的 typedef,我只想单独使用 X。
所以我正在寻找像这样的代码:
TypeChecker<X>::value_type // Here, value_type might be X or X::value_type, depending on X.
但我最初的尝试失败了,见下文:
这是一个无法编译的程序:
#include<type_traits>
template<typename T>
struct TypeChecker {
typedef typename std::conditional<
std::is_class<T>::value,
typename T::value_type, // I believe the error is due to this line (could be wrong)
T>::type value_type;
};
int main()
{
TypeChecker<int>::value_type x = 3;
return 0;
}
它给出:error: 'int' is not a class, struct, or union type
您可以在线尝试:godbolt link
我很困惑,因为我认为 std::conditional
会选择正确的分支,但从某种意义上说,它似乎正在评估两者。至少,足以导致编译错误。
帮忙?
问题是 T::value_type
作为模板参数传递给 std::conditional
,当 T
是 int
时,表达式本身无效。
您可以改用 class 模板和偏特化。
template<typename T, typename = void>
struct TypeChecker {
typedef T value_type;
};
template<typename T>
struct TypeChecker<T, typename std::enable_if<std::is_class<T>::value>::type> {
typedef typename T::value_type value_type;
};
顺便说一句:std::is_class
条件似乎松了很多;您可以将其限制为 具有成员类型 value_type
,例如
template<typename T, typename = void>
struct TypeChecker {
typedef T value_type;
};
template<typename T>
struct TypeChecker<T, std::void_t<typename T::value_type>> {
typedef typename T::value_type value_type;
};
std::conditional
没有 "short-circuit"。为了 std::conditional<C,X,Y>
甚至被实例化为 class 类型,三个模板参数必须都是实际类型。没有办法让模板与其代表非法或未知类型的模板参数之一一起使用,即使该参数并不直接重要。
您的TypeChecker
的一些解决方案:
// C++17, using partial specialization SFINAE:
template <typename T, typename Enable = void>
struct TypeChecker {
using value_type = T;
};
template <typename T>
struct TypeChecker<T, std::void_t<typename T::value_type>> {
using value_type = typename T::value_type;
};
// C++11 or later, using function SFINAE:
template <typename T>
struct type_identity { using type = T; };
template <typename T>
type_identity<typename T::value_type> TypeChecker_helper(int); // not defined
template <typename T>
type_identity<T> TypeChecker_helper(...); // not defined
template <typename T>
struct TypeChecker {
using value_type = typename decltype(TypeChecker_helper<T>(0))::type;
};
(旁白:我总是对自动 "unwrap" 东西的模板有点怀疑,就像这样 TypeChecker
。它可能会阻止特别想要使用容器或迭代器作为值的代码直接。)
我想要一个类型,它依赖于具有 X::value_type 的其他 class X。 如果另一个 class 中没有这样的 typedef,我只想单独使用 X。
所以我正在寻找像这样的代码:
TypeChecker<X>::value_type // Here, value_type might be X or X::value_type, depending on X.
但我最初的尝试失败了,见下文:
这是一个无法编译的程序:
#include<type_traits>
template<typename T>
struct TypeChecker {
typedef typename std::conditional<
std::is_class<T>::value,
typename T::value_type, // I believe the error is due to this line (could be wrong)
T>::type value_type;
};
int main()
{
TypeChecker<int>::value_type x = 3;
return 0;
}
它给出:error: 'int' is not a class, struct, or union type
您可以在线尝试:godbolt link
我很困惑,因为我认为 std::conditional
会选择正确的分支,但从某种意义上说,它似乎正在评估两者。至少,足以导致编译错误。
帮忙?
问题是 T::value_type
作为模板参数传递给 std::conditional
,当 T
是 int
时,表达式本身无效。
您可以改用 class 模板和偏特化。
template<typename T, typename = void>
struct TypeChecker {
typedef T value_type;
};
template<typename T>
struct TypeChecker<T, typename std::enable_if<std::is_class<T>::value>::type> {
typedef typename T::value_type value_type;
};
顺便说一句:std::is_class
条件似乎松了很多;您可以将其限制为 具有成员类型 value_type
,例如
template<typename T, typename = void>
struct TypeChecker {
typedef T value_type;
};
template<typename T>
struct TypeChecker<T, std::void_t<typename T::value_type>> {
typedef typename T::value_type value_type;
};
std::conditional
没有 "short-circuit"。为了 std::conditional<C,X,Y>
甚至被实例化为 class 类型,三个模板参数必须都是实际类型。没有办法让模板与其代表非法或未知类型的模板参数之一一起使用,即使该参数并不直接重要。
您的TypeChecker
的一些解决方案:
// C++17, using partial specialization SFINAE:
template <typename T, typename Enable = void>
struct TypeChecker {
using value_type = T;
};
template <typename T>
struct TypeChecker<T, std::void_t<typename T::value_type>> {
using value_type = typename T::value_type;
};
// C++11 or later, using function SFINAE:
template <typename T>
struct type_identity { using type = T; };
template <typename T>
type_identity<typename T::value_type> TypeChecker_helper(int); // not defined
template <typename T>
type_identity<T> TypeChecker_helper(...); // not defined
template <typename T>
struct TypeChecker {
using value_type = typename decltype(TypeChecker_helper<T>(0))::type;
};
(旁白:我总是对自动 "unwrap" 东西的模板有点怀疑,就像这样 TypeChecker
。它可能会阻止特别想要使用容器或迭代器作为值的代码直接。)