我试图通过使用c ++ 17中的新演绎指南来进行高级类模板参数推导。不幸的是,看起来你只能在->
之后使用简单的模板声明,但我需要一个辅助结构来确定结果类型。
我的用例是这样的:我有一个可变参数模板类,它采用任意数量的不同类型。对于一个构造函数,我想指定每一个,对于另一个ctor我只想指定一个类型并复制N次。
要在演绎指南中访问此N
,我引入了一种新类型:
template<size_t N>
struct Replicate { };
我所拥有的课程与此类似:
template<typename... Foos>
struct Foo {
// [ ... ] member std::tuple<Foos...>
// ctor 1: give values for all types (easy to deduce)
Foo(Foos&&... args /* rvalue ref, NOT forwarding */) { };
// ctor 2: give one value and N, result is N copies of this value.
// takes Replicate<N> as parameter to aid the deduction.
template<typename T, size_t N>
Foo(const T& t, Replicate<N>) { };
};
用法如下:
Foo f1{1, 2, 3.0}; // deduce Foo<int, int, double>;
Foo f2{8, Replicate<4>{}}; // deduce Foo<int, int, int, int>;
第一个的演绎指南是直截了当的:
template<typename... Ts>
Foo(Ts&&...) -> Foo<Ts...>;
第二个(ctor 2)扣除指南会出现问题。首先,我需要一个辅助结构来从Foo<T, T, ... /* total N times */, T>
和T
创建N
。
template<typename, typename, typename>
struct ExpandNTimes;
template<typename T, size_t... Is>
struct ExpandNTimes<T, std::index_sequence<Is...>> {
template<size_t> using NthType = T;
using Type = Foo<NthType<Is>...>;
};
然后在演绎指南中,我想利用帮助器推断出正确的类型。我不能直接使用Foo<something>
,因为没有任何&#34;就地参数包创建&#34;因此是辅助结构。
template<typename T, size_t N>
Foo(const T&, Replicate<N>) -> typename ExpandNTimes<T, std::make_index_sequence<N>>::Type;
不幸的是,这导致类似于这个的错误:
error: trailing return type of 'typename ExpandNTimes<T, /* std things */>::Type' deduction guide is not a specialization of ‘Foo<Ts>’
有没有办法解决这个问题?
答案 0 :(得分:6)
使用类模板参数推断这是不可能的 - 两个模板名称必须是the same,而->
之后的东西必须是simple-template-id。这并没有为模板恶作剧留下任何空间。
但是没有什么可以阻止你做类模板参数推导要替换的事情:工厂函数:
template <typename T, size_t N>
typename ExpandNTimes<T, std::make_index_sequence<N>>::Type
makeFoo(T const&, Repliace<N>);
答案 1 :(得分:1)
如果您可以更改Replicate
的定义以将包嵌入到基类中,那么这是可行的:
template<class> struct ReplicateBase {};
template<size_t N> struct Replicate : ReplicateBase<std::make_index_sequence<N>> {};
template<size_t, class T> using Meow = T;
template<typename T, size_t... Ns>
Foo(const T&, ReplicateBase<std::index_sequence<Ns...>>) -> Foo<Meow<Ns, T>...>;
然后,当传递Replicate
时,限制其他所有内容以便不与本指南竞争是一个“简单”的问题:
Foo(Foos&&... args) { }
和template<typename... Ts> Foo(Ts&&...) -> Foo<Ts...>;
(您确定要在传递左值时推断引用吗?)应限制在Foos
/ Ts
不是{{1}时}}ŠReplicate
需要加以限制,以防止它被用于推断空包(例如,到template<typename T, size_t N> Foo(const T& t, Replicate<N>);
时)