目前,我正在尝试让一些代码对不同类型做出不同的反应。这不是确切的代码,但它传达了信息。
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...>>;
Currently, I'm trying to get some code to react differently to different types. This isn't the exact code, but it gets the message across.
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;
}
I've tried more than this code shows, but nothing works so far and I ran across a problem with explicit specialization in a non-namespace scope. For reference, I'm working on gcc 4.6 (the one that comes with oneiric server), which I believe has complete variadic template support. I don't care how ugly it gets if the implementation works to detect the last argument of the parameter pack and the other types as well. Any suggestions?
EDIT:
I wanted to share the solution I used based on the answers (this is an example).
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...>>;
发布评论
评论(3)
如果您使用 clang 进行编译,它会报告 (2) 和 (3) 不可用。您希望选择的 (3) 的警告如下:
为什么
Args
不可推导? C++0x FDIS 在 §14.8.2.5/9 中规定:在您的专业化中,类型
std::tuple
是根据模板参数Args
和T< 指定的类型/代码>。它包含一个包扩展 (
Args...
),但该包扩展不是最后一个模板参数(T
是最后一个模板参数)。因此,tuple
的整个模板参数列表(
的整体)是一个非推导的上下文。std::tuple
的参数列表是模板特化的参数列表中唯一出现Args
的位置;因为它不能从那里推导,所以它根本不能推导,并且专业化永远不会被使用。Matthieu M. 在他的答案中提供了一个巧妙的解决方法。
If you compile using clang, it helpfully reports that (2) and (3) are unusable. The warning for (3), which you expect to be selected, is as follows:
Why is
Args
not deducible? The C++0x FDIS states at §14.8.2.5/9:In your specialization, the type
std::tuple<Args..., T>
is a type that is specified in terms of template parametersArgs
andT
. It contains a pack expansion (Args...
), but that pack expansion is not the last template argument (T
is the last template argument). Thus, the entire template argument list of thetuple
(the entirety of<Args..., T>
) is a non-deduced context.The argument list of the
std::tuple
is the only place in the template specialization's argument list thatArgs
appears; since it is not deducible from there, it is not deducible at all and the specialization will never be used.Matthieu M. provides a clever workaround in his answer.
@James 提供了原因,现在让我们尝试寻找替代方案。
我建议使用另一个间接级别。
1.获取最后一个参数
2.引入专门的帮手
3.连接起来
请注意,空元组没有最后一种类型,因此我必须在单独的专业化中处理它们。
@James provided the why, now let's try to find an alternative.
I would suggest using another level of indirection.
1. Getting the last argument
2. Introducing a specialized helper
3. Hooking it up
Note that there is no last type for empty tuples, so I had to deal with them in a separate specialization.
如果你想知道一个元组是否作为特定的最后一个成员,这里有一个类型特征:
编辑:哦,我没有看到Matthieu已经写了完全相同的东西。没关系。
If you like to find out whether a tuple as a specific last member, here's a type trait for that:
Edit: Oh, I didn't see that Matthieu had already written the exact same thing. Never mind.