使用类模板的模板参数推导

时间:2017-06-03 03:44:58

标签: c++ templates c++17 forwarding forwarding-reference

我在这里阅读关于类模板的模板参数推导的文章http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0091r3.html。这个功能是在C ++ 17标准中,有些东西让我很困惑。

template <typename T>
class Something {
public:

    // delete the copy and move constructors for simplicity
    Something(const Something&) = delete;
    Something(Something&&) = delete;

    explicit Something(T&&) { ... }
    explicit Something(const T&) { ... }

    template <typename U, typename EnableIfNotT<U, T>* = nullptr>
    Something(U&&) { ... }
};

鉴于上述代码,如果有人试图像这样实例化上述模板的实例

auto something = Something{std::shared_ptr<int>{}};

是否会调用右值引用过载?由于考虑扣除的过载集是

template <typename T>
Something<T> F(T&&) { ... }
template <typename T>
Something<T> F(const T&) { ... }
template <typename T, typename U, typename EnableIfNotT<U, T>*>
Something<T> F(U&&) { ... }
  1. 第二个重载永远不会优先于第一个重载(因为它现在是转发引用重载,而不是rvalue引用重载),那么应该在这里发生什么?
  2. 如果没有明确指定T参数,似乎永远无法调用最后一个,这是预期的行为吗?
  3. 在为类模板使用模板参数推导时,还应该记住任何其他陷阱或样式指南吗?
  4. 还有用户定义的演绎指南需要在课程定义之后吗?例如,您可以在类定义本身的类构造函数的声明中具有尾随返回类型吗? (与迭代器构造函数http://en.cppreference.com/w/cpp/language/class_template_deduction
  5. 不同

1 个答案:

答案 0 :(得分:2)

  
      
  1. 第二个重载永远不会优先于第一个重载(因为现在是转发引用重载,而不是rvalue引用重载),所以本应该发生什么?
  2.   

不,不是转发参考。这是一个关键的区别。来自[temp.deduct.call]

  

转发引用是对cv-unqualified模板参数的rvalue引用,该参数不表示类模板的模板参数(在类模板参数推断期间([over.match.class.deduct] ]))。

您的候选人是:

WebClient.UploadFile

当你写:

template <typename T>
Something<T> F(T&&);       // this ONLY matches non-const rvalues

template <typename T>
Something<T> F(const T&);  // this matches everything

template <typename T, typename U, typename EnableIfNotT<U, T>*>
Something<T> F(U&&);       // this matches nothing

首选auto something = Something{std::shared_ptr<int>{}}; 构造函数,T&&,因此您最终会使用T=std::shared_ptr<int>作为类模板特化。如果改为写了:

Something<std::shared_ptr<int>>

然后std::shared_ptr<int> p; auto something = Something{p}; 构造函数是首选(实际上它是唯一可行的候选者)。虽然我们最终在同一个地方:T const&

  
      
  1. 如果没有明确指定T参数,似乎永远无法调用最后一个,这是预期的行为吗?
  2.   

正确,Something<std::shared_ptr<int>>是一个非推断的上下文。这是有道理的 - 这个构造函数用于进行转换,但您需要指定要将转换为的内容才能进行转换。让这个“正常工作”永远不会有意义。

  
      
  1. 此外,用户定义的演绎指南还需要在课程定义之后吗?
  2.   

是。根据规则,这就是他们去的地方。在构造函数中使用尾部返回类型没有意义 - 构造函数不会“返回”任何内容。