3

我试图构建一个可变模板类。通常情况下,实例化的每个级别需要通过切分一个类型然后使用余数来实例化“下一级”。对于我的最后一个层次,而不是专门研究一种类型,我宁愿提供一些基本的案例类型,并避免重复实际的逻辑。std :: conditional的模板化差异使用,其中一种类型是实例化故障

我添加了std::conditional来打开BaseCase,其余的类型由一个空的参数包组成。

class BaseCase { }; 

template <typename T, typename... Ts> 
class VariadicClass; 

template <typename... Ts> 
using NextLevel = typename std::conditional< 
    sizeof...(Ts) != 0, VariadicClass<Ts...>, BaseCase>::type; 

template <typename T, typename... Ts> 
class VariadicClass { 
    T this_level; // whatever 
    NextLevel<Ts...> next_level; // fails when Ts is empty 
}; 

问题VariadicClass上的至少一种类型参数模板,所以当它击中基础案例(Ts为空),试图使用std::conditional使用VariadicClass<>,这当然会失败。

我管理的解决方案是编写一些特定的功能,并使用decltype以及重载,根本不使用std::conditional

template <typename... Ts> 
VariadicClass<Ts...> type_helper(Ts&&...); 

BaseCase type_helper(); 

template <typename... Ts> 
using NextLevel = decltype(type_helper(std::declval<Ts>()...)); 

现在,这个工作,但如果我想每次有一个可变类,我想要保持这种做法,这似乎很乏味。有没有办法使用std::conditional或类似的东西来实现这种效果,而不必写出太多问题特定的代码?

回答

4

推迟评价。

template<class T>struct identity{ 
    template<class...>using result=T; 
}; 
template<template<class...>class src> 
struct delay{ 
    template<class...Ts>using result=src<Ts...>; 
}; 

template <typename... Ts> 
using NextLevel = 
typename std::conditional< 
    sizeof...(Ts) != 0, delay<VariadicClass>, identity<BaseCase> 
>::type::template result<Ts...>; 

identity忽略Ts...和返回它的参数。 delay需要template并应用Ts...。虽然签名看起来很可疑,但它起作用。

4

为什么不

class BaseCase { }; 

template <typename... Ts> 
class VariadicClass; // undefined base template 

template <typename... Ts> 
using NextLevel = typename std::conditional< 
    sizeof...(Ts) != 0, VariadicClass<Ts...>, BaseCase>::type; 

template <typename T, typename... Ts> 
class VariadicClass<T, Ts...> { // partial specialization for having at least 1 type parameter 
    T this_level; // whatever 
    NextLevel<Ts...> next_level; 
}; 
+0

你也可以实现'BaseCase'作为'VariardicClass <>'专业化,完全摆脱'NextLevel'。 – Yakk 2014-08-28 15:59:03

0

或者,你可以专注VariadicClass<T>

class BaseCase {}; 

// general case 
template <typename T, typename... Ts> 
class VariadicClass { 
    T this_level; // whatever 
    VariadicClass<Ts...> next_level; 
}; 

// specialization 
template <typename T> 
class VariadicClass<T> { 
    T this_level; // whatever 
    BaseClass next_level; 
}; 
+0

这是我试图避免做的事情 – 2014-08-28 15:20:24

2

阅读T.C.'s answer和Yakk的评论后,我意识到我可以用两个专业写为一个模板类,而不是写另一BaseClass和类型别名。

template <typename... Ts> 
class VariadicClass; 

// specialization gets everything but an empty Ts 
template <typename T, typename... Ts> 
class VariadicClass<T, Ts...> { 
    VariadicClass<Ts...> next_level; 
    // normal case 
}; 

template <> 
class VariadicClass<> { // instead of class BaseCase 
    // base case 
};