如何解决这个问题:
template<class T>
struct ResultType
{
using type = std::conditional_t<std::is_class_v<T>, typename T::result_type, void>;
};
如果 T 不是类类型,那么它不能应该返回 void,而是:
<块引用>错误:'int' 不是类、结构或联合类型
24 | using type = std::conditional_tstd::is_class_v
所以我不需要尝试调用错误表达式,但是如何调用?
答案 0 :(得分:6)
以下内容:
using type = std::conditional_t<std::is_class_v<T>, typename T::result_type, void>;
部分 typename T::result_type
将在 T = int
时失败,因为 typename int::result_type
格式错误。
您可以通过使用模板特化而不是 std::conditional
来解决此问题,后者执行完全相同的操作,但在 T::result_type
不是类类型时避免执行 T
:
#include <type_traits>
template <typename T, typename = void>
struct ResultType;
template <typename T>
struct ResultType<T, std::enable_if_t<!std::is_class_v<T>>> {
using type = void;
};
template<typename T>
struct ResultType<T, std::enable_if_t<std::is_class_v<T>>> {
using type = typename T::result_type;
};
// ...
struct X {
using result_type = int;
};
int main() {
static_assert(std::is_same_v<typename ResultType<X>::type, typename X::result_type>, "FAIL!");
static_assert(std::is_same_v<typename ResultType<int>::type, void>, "FAIL!");
}
答案 1 :(得分:3)
std::conditional_t
是在两种类型之间进行选择,但是当 T = int
时 T::result_type
不是类型。您可以使用 sfinae:
#include <type_traits>
template <typename T, typename = void>
struct result_type_or_void {
using type = void;
};
template <typename T>
struct result_type_or_void<T,std::void_t<typename T::result_type>> {
using type = typename T::result_type;
};
template<class T>
struct ResultType
{
using type = typename result_type_or_void<T>::type;
};
struct Test {
using result_type = int;
};
int main() {
ResultType<int> t;
static_assert( std::is_same_v<ResultType<int>::type,void>);
static_assert( std::is_same_v<ResultType<Test>::type,int>);
}
答案 2 :(得分:0)
失败是因为 std::conditional
selects 两个类型表达式之一——但此时类型表达式已经被评估。由于 int
不是一个类,并且没有 result_type
- 它会出错。
正如其他人所指出的,这可以通过 enable_if
或 void_t
使用 SFINAE 解决——但另一种方法是利用表达式 SFINAE 的函数重载,而不是需要部分特化:
template <typename T, typename Default = void>
class ResultType
{
static auto test(...) -> Default;
template <typename U>
static auto test(const U&) -> typename U::result_type;
public:
using type = decltype(test(std::declval<T>()));
};
当T
是定义result_type
的类型时,test(const U&)
分支被启用并被选中进行重载解析;否则 test(...)
被选中用于其他所有内容并变为 Default
(在本例中为 void
)。
然后通过评估表达式以查看选择了哪个重载,使用 decltype
推导出类型。