我尝试编写IsLast
类型特征来检查给定类型是否是std::tuple
中的最后一个,但下面的代码不能编译。我知道如何绕过它,但我很好奇为什么编译器不喜欢它。我猜我必须有一些关于variadic-template特化的规则,我不知道。
代码位于:https://godbolt.org/g/nXdodx
错误讯息:
error: implicit instantiation of undefined template
'IsLast<std::tuple<std::__cxx11::basic_string<char>, int>, int>'
专业化声明也有警告:
警告:类模板部分特化包含无法推导出的模板参数;这部分专业化将永远不会被使用
#include <tuple>
#include <string>
/////////This works
template<typename TP, typename T>
struct IsFirst;
template<typename U, typename ...V, typename T>
struct IsFirst <std::tuple<U, V...>, T>
{
enum {value = false};
};
template<typename U, typename ...V>
struct IsFirst <std::tuple<U, V...>, U>
{
enum {value = true};
};
////////This doesn't compile
template<typename TP, typename T>
struct IsLast;
template<typename ...U, typename V, typename T>
struct IsLast <std::tuple<U..., V>, T>
{
enum {value = false};
};
template<typename ...U, typename V>
struct IsLast <std::tuple<U..., V>, V>
{
enum {value = true};
};
int main()
{
using T = std::tuple<std::string, int>;
bool v1 = IsFirst<T, std::string>::value;
bool v2 = IsLast <T, int>::value;
}
答案 0 :(得分:9)
在类模板中,参数包必须在所有其他模板参数之后,因此不允许这样的事情。
template<typename U, typename ...V, typename T>
struct IsFirst <std::tuple<U, V...>, T>
{
enum {value = false};
};
在功能模板中,只有在可以推断出包装后,才能在包装后面显示其他模板参数。类模板不允许这样做,因为它们不允许扣除。
答案 1 :(得分:3)
通过复活观察,可变参数模板必须处于最后位置。
但是还有很多其他方法可以获得相同的结果。
显而易见的解决方案是创建递归类型特征,但我向您展示了基于true
的解决方案
std::tuple_element
观察此#include <tuple>
#include <iostream>
#include <type_traits>
template <typename C, typename T>
struct IsLast;
template <template <typename ...> class C, typename T, typename ... Ts>
struct IsLast<C<Ts...>, T>
{
using Tl
= typename std::tuple_element<sizeof...(Ts)-1U, std::tuple<Ts...>>::type;
static constexpr bool value { std::is_same<Tl, T>::value };
};
int main ()
{
using T = std::tuple<std::string, int>;
std::cout << IsLast<T, int>::value << std::endl; // print 1
std::cout << IsLast<T, long>::value << std::endl; // print 0
}
与
IsLast
以及其他模板类。
答案 2 :(得分:2)
如果P的模板参数列表包含的包扩展不是最后一个模板参数,则整个模板参数列表是非推导的上下文
请注意,仅在模板的参数列表中,包必须是最后一个。模板参数包不需要是模板参数列表中的最后一个,这可以是模板类部分特化或模板函数的情况。
所以你的第一个类模板部分特化的例子是正确的:
template<typename U, typename ...V>
struct IsFirst <std::tuple<U, V...>, U>
{
enum {value = true};
}
因为V...
是tuple
的最后一个参数。
template<typename ...V,typename U>
struct IsFirst <std::tuple<V..., U>, U>
{
enum {value = true};
};
因为V...
不是tuple
的最后一个参数。
答案 3 :(得分:0)
有一个更好的解决方案:
#include <tuple>
#include <string>
#include <type_traits>
int main()
{
using T = std::tuple<std::string, int>;
constexpr size_t size = std::tuple_size<T>::value;
typedef decltype(std::get<size - 1>(std::declval<T>())) LastType;
static_assert(std::is_same<std::decay_t<LastType>, int>::value, "no");
}