5

目前,我正在尝试让一些代码对不同的类型做出不同的反应。这不是确切的代码,但它传达了信息。

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...>>;
4

3 回答 3

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>是根据模板参数ArgsT. 它包含一个包扩展 ( Args...),但该包扩展不是最后一个模板参数(T是最后一个模板参数)。tuple因此,(整个)的整个模板参数列表<Args..., T>是非推导上下文。

的参数列表std::tuple是模板特化的参数列表中唯一Args出现的位置;因为它不能从那里推导出来,所以它根本不能推导出来,并且永远不会使用专业化。

Matthieu M.在他的回答中提供了一个聪明的解决方法

于 2011-07-20T06:28:01.900 回答
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 };
};

请注意,空元组没有最后一种类型,因此我必须在单独的专业中处理它们。

于 2011-07-20T07:22:54.920 回答
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;
};

编辑:哦,我没有看到马蒂厄已经写了完全相同的东西。没关系。

于 2011-07-20T19:38:33.550 回答