目前,我正在尝试让一些代码对不同类型做出不同反应。这不是确切的代码,但它会传递信息。
template<class A, class B>
struct alpha {
enum { value = 0 };
};
template<class T, class... Args>
struct alpha<std::tuple<Args...>, T> {
enum { value = 1 };
};
// This gets ignored
template<class T, class... Args>
struct alpha<std::tuple<Args..., std::vector<T> >, T> {
enum { value = 2 };
};
// This gets ignored
template<class T, class... Args>
struct alpha<std::tuple<Args..., T>, T> {
enum { value = 3 };
};
template<class T, class... Args>
struct alpha<T, std::tuple<Args...> > {
enum { value = 4 };
};
template<class... LArgs, class... RArgs>
struct alpha<std::tuple<LArgs...>, std::tuple<RArgs...> > {
enum { value = 5 };
};
int main(int argc, char* argv[]) {
std::cout << alpha<std::tuple<int, double>, double>::value << std::endl; // prints 1
return 0;
}
我尝试的不仅仅是这个代码显示,但到目前为止没有任何工作,我遇到了在非命名空间范围内显式特化的问题。作为参考,我正在研究gcc 4.6(oneiric服务器附带的那个),我认为它具有完整的可变参数模板支持。如果实现检测参数包的最后一个参数以及其他类型,我不在乎它有多难看。有什么建议吗?
编辑: 我想根据答案分享我使用的解决方案(这是一个例子)。
template<typename T> struct tuple_last;
template<typename T, typename U, typename... Args>
struct tuple_last<std::tuple<T,U,Args...>> {
typedef typename tuple_last<std::tuple<U,Args...>>::type type;
};
template<typename T>
struct tuple_last<std::tuple<T>> {
typedef T type;
};
namespace details {
// default case:
template<class T, class U>
struct alpha_impl {
enum { value = 1 };
};
template<class T>
struct alpha_impl<T, T> {
enum { value = 101 };
};
template<class T>
struct alpha_impl<T, std::vector<T>> {
enum { value = 102 };
};
// and so on.
}
template<class T, class... Args>
struct alpha<std::tuple<Args...>, T>
: details::alpha_impl<T, tuple_last<std::tuple<Args...>>;
答案 0 :(得分:13)
如果使用clang进行编译,则会有助于报告(2)和(3)无法使用。您希望选择的(3)警告如下:
警告:类模板部分特化包含一个无法推导出的模板参数;这部分专业化将永远不会被使用
struct alpha<std::tuple<Args..., T>, T> { ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
注意:不可扣除的模板参数“
Args
”template<class T, class... Args> ^
为什么Args
无法推断? C ++ 0x FDIS状态见§14.8.2.5/ 9:
如果[根据模板参数指定的类型]的模板参数列表包含的包扩展不是最后一个模板参数,则整个模板参数列表是非推导的上下文。
在您的专业化中,类型std::tuple<Args..., T>
是根据模板参数Args
和T
指定的类型。它包含一个包扩展(Args...
),但该包扩展不是最后一个模板参数(T
是最后一个模板参数)。因此,tuple
(整个<Args..., T>
)的整个模板参数列表是一个非推断的上下文。
std::tuple
的参数列表是模板专精化参数列表中Args
出现的唯一位置;因为它不能从那里推导出来,所以根本不可推论,专业化永远不会被使用。
Matthieu M. provides a clever workaround in his answer。
答案 1 :(得分:12)
@James提供了原因,现在让我们尝试寻找替代方案。
我建议使用另一级别的间接。
<强> 1。获得最后一个论点
template <typename T> struct Last;
template <typename T, typename U, typename... Args>
struct Last<std::tuple<T,U,Args...>>
{
typedef typename Last<std::tuple<U,Args...>>::type type;
};
template <typename T>
struct Last<std::tuple<T>>
{
typedef T type;
};
<强> 2。介绍专业助手
template <typename T, typename U>
struct alpha_tuple
{
enum { value = 1 };
};
template <typename T>
struct alpha_tuple<T,T>
{
enum { value = 3 };
};
template <typename T>
struct alpha_tuple<std::vector<T>,T>
{
enum { value = 2; }
};
第3。把它挂起来
template <typename T>
struct alpha<std::tuple<>, T>
{
enum { value = 1 };
};
template <typename T, typename U, typename Args...>
struct alpha<std::tuple<U, Args...>, T>
{
typedef typename Last<std::tuple<U, Args...>>::type LastType;
enum { value = alpha_tuple<LastType,T>::value };
};
请注意,空元组没有最后一种类型,因此我必须在单独的专门化中处理它们。
答案 2 :(得分:1)
如果你想知道一个元组是否是一个特定的最后一个成员,这里是一个类型特征:
#include <type_traits>
#include <tuple>
template <typename ...Args> struct back;
template <typename T, typename ...Args> struct back<T, Args...>
{ typedef typename back<Args...>::type type; };
template <typename T> struct back<T>
{ typedef T type; };
template <typename...> struct tuple_has_last : public std::false_type {};
template <typename T, typename... Args> struct tuple_has_last<T, std::tuple<Args...>>
{
static const bool value = std::is_same<typename back<Args...>::type, T>::value;
};
编辑:哦,我没有看到Matthieu已经写了完全相同的东西。没关系。