尾随返回类型的演绎指南不是专业化

时间:2018-03-20 16:26:13

标签: c++ templates c++17

我试图通过使用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>’

有没有办法解决这个问题?

2 个答案:

答案 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>);时)