扣除指南和可变参数模板

时间:2017-06-02 23:09:32

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

请考虑以下代码:

#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...) {}

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

1 个答案:

答案 0 :(得分:4)

这是gcc bug 80871。以下是对代码格式正确的解释(并且在确定import tensorflow as tf import numpy as np # tf.constant(value, dtype=None, shape=None, # name='Const', verify_shape=False) a = tf.constant([2, 2], name="a") b = tf.constant([[0, 1], [2, 3]], name="b") x = tf.add(a, b, name="add") y = tf.multiply(a, b, name="mul") # verify_shape=True, error if shape not match # edge1 = tf.constant(2, dtype=None, shape=[2,2], name="wrong_shape", verify_shape=True) # verify_shape=False, if shape not match, will add to match edge2 = tf.constant(2, dtype=None, shape=[2,2], name="edge2", verify_shape=False) # increase row by row, from left to right edge3 = tf.constant([1,2,3,4], dtype=None, shape=[4,3], name="edge3", verify_shape=False) # reassign works edge2c = edge2 edge3c = edge3 edge4 = tf.constant(np.ones((2,2)), dtype=None, shape=None, name="shape22", verify_shape=False) # increase row by row, from left to right edge5 = tf.constant(np.ones((4,3)), dtype=None, shape=[4,3], name="shape43", verify_shape=False) with tf.Session() as sess: writer = tf.summary.FileWriter('./log/01_tf', sess.graph) x, y = sess.run([x, y]) sess.run(edge4) sess.run(edge5) sess.run(edge2c) sess.run(edge3c) writer.close() t2时,clang是正确的。)

了解如何处理

的过程
custom_tuple<int>

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

custom_tuple t2(42);

从这一点来看,它是根据你对&#34;尾随参数包&#34;的解释来选择你自己的冒险。根据{{​​3}}:

  

未以其他方式推导出的尾随模板参数包将被推导为空的模板参数序列。如果可以推导出所有模板参数,则可以省略它们;在这种情况下,空模板参数列表template <class... T, class... Args> custom_tuple<T...> foo(Args... ); // the constructor template <class... Args> custom_tuple<Args...> foo(Args... ); // the deduction guide 本身也可以省略。

<>并非落后

这种情况很简单。我们只有一个可行的候选人(因为T...不可扣除) - 扣除指南候选人。我们将T...推断为Args...,因此最终得到{int}

custom_tuple<int>正在落后

gcc和clang实际上都会考虑演绎成功的演绎。所以我们去了[temp.arg.explicit]/3

中的tiebreakers
  

鉴于这些定义,如果[...]

,可行函数T...被定义为更好函数而不是另一个可行函数F1。      
      
  • F2F1是函数模板特化,F2的函数模板比​​F1的模板更专业,根据[[1}}中描述的部分排序规则[ temp.func.order],或者,如果不是,
  •   
  • F2是从演绎指南([over.match.class.deduct])生成的,F1不是,或者,如果不是,[...]
  •   

出于部分排序的目的,[over.match.best]只是与函数参数对应的那些,我们被允许relevant types,因此两个函数模板都不被认为比另一个更专业。

这让我们只是更喜欢演绎指南,这是整个过程中最简单的一步。我们将F2推断为Args...,因此最终得到{int}

无论哪种方式,custom_tuple<int>都是正确的决定。