我在c++中玩参数包,下面是我想要实现的:
我有这3个结构:
struct Base {
Base(int x) : x(41) {}
int x;
};
struct A : Base {
A() : Base(41) {}
};
struct B : Base {
B() : Base(42) {}
};
我想创建一个泛型函数,它返回一个元组,其中包含指定类型的实例,即
magicFunction<A,B,A,B,A> == std::tuple{A(), B(), A(), B(), A()}
magicFunction<A,B,A> == std::tuple{A(), B(), A()}
我试图使用模板专业化来扩展类型,但不幸的是无法做到(我理解它为什么不编译,只是不知道如何修复它:(
template<typename isEmpty, typename ...T>
struct ExpanderImpl {
};
template<typename Head, typename ... Rest>
struct ExpanderImpl<std::false_type, Head, Rest...> {
static std::tuple<Head, Rest...> getValues() {
if(sizeof...(Rest) > 0) {
return std::tuple_cat(std::tuple{Head()}, ExpanderImpl<std::false_type, Rest...>::getValues());
} else {
return std::tuple_cat(std::tuple{Head()}, ExpanderImpl<std::true_type, Rest...>::getValues());
}
}
};
template<typename ...Empty>
struct ExpanderImpl<std::true_type, Empty...> {
static std::tuple<Empty...> getValues() {
return {};
}
};
template<typename ...T>
struct Expander {
static std::tuple<T...> getValues() {
if(sizeof...(T) > 0) {
return ExpanderImpl<std::false_type, T...>::getValues();
} else {
return ExpanderImpl<std::true_type, T...>::getValues();
}
}
};
关于如何修复它,有什么建议吗?还有,有没有更好的方法来实现我想要的?
完整的代码可以在这里找到。谢谢你的帮助。
您想要的是
template <typename... T> std::tuple<T...> magicFunction()
{
return {};
}
你会称之为
magicFunction<A,B,A,B,A>();
并且它将返回一个CCD_ 1。它的工作方式是return {};
说返回一个初始化的值(T()
/T{}
(返回值,返回值是std::tuple<T...>
,它是所有模板参数的元组
您似乎在寻找
template <typename... T>
using magicFunction = std::tuple<T...>;
int main() {
magicFunction<A,B,A>();
// If no default constructors supplied.
magicFunction<Base,Base,Base>(41, 42, 41);
}
-
尽管有更简单的方法来创建元组,但您的方法失败了,因为两个分支都应该用常规
if
实例化。if constexpr
(C++17(解决了这个Demo。请注意,
std::tuple{Head()}
也是C++17构造。C++11将是CCD_ 9或CCD_。
-
将实现保持在C++11中的方法是去掉这个运行时
std::tuple<A,B,A,B,A>
1,并使用std::conditional
使用std::true_type
/std::false_type
template<typename Head, typename ... Rest> struct ExpanderImpl<std::false_type, Head, Rest...> { static std::tuple<Head, Rest...> getValues() { return std::tuple_cat( std::make_tuple(Head()), ExpanderImpl<typename std::conditional<(sizeof...(Rest) == 0), std::true_type, std::false_type>::type, Rest...>::getValues()); } }; template<typename ...T> struct Expander { static std::tuple<T...> getValues() { return ExpanderImpl<typename std::conditional<(sizeof...(T) == 0), std::true_type, std::false_type>::type, T...>::getValues(); } };
演示。
-
你可以通过不同的专业化来摆脱
is_empty
:template<typename ...Ts> struct Expander; // Non empty case template<typename Head, typename ... Rest> struct Expander<Head, Rest...> { static std::tuple<Head, Rest...> getValues() { return std::tuple_cat( std::make_tuple(Head()), Expander<Rest...>::getValues()); } }; // Empty case template<> struct Expander<> { static std::tuple<> getValues() { return {}; } };
演示。