【问题标题】:Deduction guide and variadic templates演绎指南和可变参数模板
【发布时间】:2017-06-02 23:09:32
【问题描述】:

考虑以下代码:

#include <tuple>
#include <iostream>

template <class T>
struct custom_wrapper
{
    template <class Arg>
    custom_wrapper(Arg arg): data(arg) {}
    T data;
};

template <class Arg>
custom_wrapper(Arg arg) -> custom_wrapper<Arg>;

template <class... T>
struct custom_tuple
{
    template <class... Args>
    custom_tuple(Args... args): data(args...) {}
    std::tuple<T...> data;
};

template <class... Args>
custom_tuple(Args... args) -> custom_tuple<Args...>;

int main(int argc, char* argv[])
{
    custom_wrapper<int> w1(42);  // OK
    custom_wrapper w2(42);       // OK
    custom_tuple<int> t1(42);    // OK
    custom_tuple t2(42);         // Fails
    return 0;
}

在g++7下失败的行返回如下错误:

variadic_deduction_guide.cpp: In instantiation of 'custom_tuple<T>::custom_tuple(Args ...) [with Args = {int}; T = {}]':
variadic_deduction_guide.cpp:31:23:   required from here
variadic_deduction_guide.cpp:19:45: error: no matching function for call to 'std::tuple<>::tuple(int&)'
     custom_tuple(Args... args): data(args...) {}

这是正常的还是编译器的错误?

【问题讨论】:

    标签: c++ g++ tuples c++17 template-argument-deduction


    【解决方案1】:

    这是gcc bug 80871。下面解释了为什么代码格式正确(并且当确定 t2custom_tuple&lt;int&gt; 时,clang 是正确的)。


    弄清楚如何处理的过程

    custom_tuple t2(42);
    

    基本上涉及合成一堆函数并对它们执行重载解析。相关的候选者是来自一个构造函数和推导指南的综合函数:

    template <class... T, class... Args>
    custom_tuple<T...> foo(Args... );     // the constructor
    
    template <class... Args>
    custom_tuple<Args...> foo(Args... );  // the deduction guide
    

    从这一点开始,您可以根据[temp.arg.explicit]/3 对“尾随参数包”的解释来选择自己的冒险:

    一个尾随模板参数包没有被推导出来,将被推导出为一个空的模板参数序列。如果所有的模板参数都可以推导出来,那么它们都可以被省略;在这种情况下,空模板参数列表&lt;&gt; 本身也可以省略。

    T... 没有尾随

    这个案子很简单。我们只有一个可行的候选人(因为T... 不可推演) - 推演指南候选人。我们将Args... 推断为{int},所以我们最终得到custom_tuple&lt;int&gt;

    T... 尾随

    gcc 和 clang 实际上都认为构造函数的推导成功。所以我们去[over.match.best]的决胜局:

    鉴于这些定义,一个可行的函数F1 被定义为比另一个可行的函数F2更好 函数如果 [...]

    • F1F2 是函数模板特化,根据 [temp.func.order] 中描述的偏序规则,F1 的函数模板比​​ F2 的模板更特化,或者,如果不是那,
    • F1 是从演绎指南 ([over.match.class.deduct]) 生成的,而 F2 不是,或者,如果不是,[...]

    出于偏序的目的,relevant types 只是对应于函数参数的那些,我们可以使用ignore unused template parameters,因此没有一个函数模板被认为比另一个更专业。

    这让我们更喜欢演绎指南,这是整个过程中最简单的一步。我们将Args... 推断为{int},所以我们最终得到custom_tuple&lt;int&gt;


    无论哪种方式,custom_tuple&lt;int&gt; 都是正确的决定。

    【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-09-23
    • 2020-05-09
    • 1970-01-01
    • 2023-03-28
    • 2021-06-20
    • 2021-09-12
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多