考虑
template<
typename A,
template<typename, typename...> class B,
typename C = default_type,
typename ... D
> struct D : B<A,D...>
{ /*text*/ };
现在当可变参数D
不为空/无效时,即使需要C
,也必须明确定义参数default_type
。
我试图避免这种情况,即我只想在C
时明确定义default_type
。
我在考虑像
这样的东西template<
typename A,
template<typename, typename...> class B,
typename EncapsulatedVariadicD,
typename C = default_type
> struct D : B<A,EncapsulatedVariadicD::D...>
{ /*text*/ };
但不确定是否可行,如果是,那么如何定义EncapsulatedVariadicD
。
欢迎任何替代/工作解决方案。
答案 0 :(得分:3)
通常,当您需要封装类型列表时,可以使用std::tuple
。
你可以这样:
template <
template <typename, typename...> class B,
typename A,
typename Pack
>
struct Base;
template <
template <typename, typename...> class B,
typename A,
typename... D
>
struct Base<B, A, std::tuple<D...>>
{
using type = B<A, D...>;
};
template<
typename A,
template<typename, typename...> class B,
typename PackedD,
typename C = default_type
>
struct D : Base<B, A, PackedD>::type
{ /*text*/ };
并像这样使用它:
D<SomeB, std::tuple<D1, D2>>
引用您的评论:
如果
C
不是默认值且PackedD
为空,则必须将其明确提供为std::tuple<>
,否则可能是此参数的默认值。我猜我不能两种方式,这是真的吗?
如果您不介意您的模板在内部变得更加复杂,那么可以双向拥有它。以下是:
// Unique type, internal marker for "use default template argument"
struct UseDefault {};
// GoalChooser has internal `type` which will hold the actual definition
template <
typename A,
template <typename, typename...> class B,
typename Arg1,
typename Arg2
>
struct GoalChooser;
template <
typename A,
template <typename, typename...> class B,
typename C,
typename... D
>
struct GoalChooser<A, B, C, std::tuple<D...>>
{
struct type : B<A, D...>
{
// Your original definition of class template D goes here
};
};
template <
typename A,
template <typename, typename...> class B,
typename C,
typename... D
>
struct GoalChooser<A, B, std::tuple<D...>, C>
{
using type = typename GoalChooser<A, B, C, std::tuple<D...>>::type;
};
// GetArg applies appropriate default template arguments as applicable
template <
typename Arg1,
typename Arg2
>
struct GetArg
{
using arg1 = Arg1;
using arg2 = Arg2;
};
template <
typename Arg
>
struct GetArg<UseDefault, Arg> : GetArg<Arg, UseDefault> {};
template <
typename... T
>
struct GetArg<std::tuple<T...>, UseDefault>
{
using arg1 = std::tuple<T...>;
using arg2 = default_type;
};
template <
typename C
>
struct GetArg<C, UseDefault>
{
using arg1 = C;
using arg2 = std::tuple<>;
};
template <>
struct GetArg<UseDefault, UseDefault>
{
using arg1 = default_type;
using arg2 = std::tuple<>;
};
// Client code will use this
template <
typename A,
template <typename, typename...> class B,
typename Arg1 = UseDefault,
typename Arg2 = UseDefault
>
using D = typename GoalChooser<
A,
B,
typename GetArg<Arg1, Arg2>::arg1,
typename GetArg<Arg1, Arg2>::arg2,
>::type;
我们的想法是客户端代码使用D
(现在已成为别名模板)并且可以传递std::tuple
(表示其D...
参数)或其他类型(指示它的C
参数),或者两者都没有,或者两者都是(按任意顺序,偶数)。
适当的默认参数的应用由GetArg
完成,然后由GoalChooser
处理别名的解析。
这假设C
的值永远不会是std::tuple
。如果这不是可接受的限制,则可以krzaq's answer的精神使用自定义类型而不是std::tuple
来规避它。
(请注意,此解决方案不再需要我的第一个答案中的Base
帮助程序。)
答案 1 :(得分:3)
使用打包类型,我们称之为type_list
。如果您不需要关心保留实例,也可以使用std::tuple
。
template<typename... Ts>
struct type_list{};
然后专门为您设计模板:
template<typename A, template<typename, typename...> class B,
typename TypeList, typename C = default_type>
struct D;
template<typename A, template<typename, typename...> class B,
typename... TypesInTheList, typename C>
struct D<A,B,type_list<TypesInTheList...>,C> : B<A, TypesInTheList...>
{
using parent = B<A, TypesInTheList...>;
};
您可以按预期使用它:
D<int, some_b, type_list<float, char, double>>