不好意思问题题目有点绕,请看以下类模板代码
#pragma once
#include <functional>
#include <type_traits>
template <typename... Types>
class Tuple;
template <typename Head, typename... Tail>
class Tuple<Head, Tail...>
{
private:
Head head;
Tuple<Tail...> tail;
public:
Tuple() {};
Tuple(Head const& h, Tuple<Tail...> const& t) : head(h), tail(t) {}
Tuple(Head const& h, Tail const& ... t) : head(h), tail(t...) {}
template <typename VHead, typename... VTail> \\ 构造函数 1
Tuple(VHead&& vhead, VTail&&... vtail) : head(std::forward<VHead>(vhead)), tail(std::forward<VTail>(vtail)...) {}
template <typename VHead, typename... VTail> \\ 构造函数 2
Tuple(Tuple<VHead, VTail...> const & other) : head(other.getHead()), tail(other.getTail()) {}
Head& getHead() {
return head;
}
Head const & getHead() const {
return head;
}
Tuple<Tail...> & getTail() {
return tail;
}
Tuple<Tail...> const & getTail() const {
return tail;
}
};
template <>
class Tuple<> {};
当我们试图以一个 Tuple 类型来构造另外一个 Tuple 的时候,有两种情况,一种是构造相同模板参数 tuple,另一种是构造不同但可以相互转换的模板参数,代码如下:
Tuple<int, double, string> t(17, 3.14, "Hello world");
Tuple<long int, long double, string> b = t; \\ 情形 1
Tuple<long int, long double, string> b = t; \\ 情形 2
在这个类模板定义下,上述代码是编译不过去的,原因是构造函数 1 的优先级比构造函数 2 高,所以编译器没有调用复制构造函数 2 。因此我们需要用std::enable_if_t
去 disable 构造函数,所以构造函数 1 和 2 可以被改写为下面两种:
第一种:std::enable_if_t
为默认模板参数
template <typename VHead, typename... VTail, typename = std::enable_if_t<sizeof...(VTail)==sizeof...(Tail) > >
Tuple(VHead&& vhead, VTail&&... vtail) : head(std::forward<VHead>(vhead)), tail(std::forward<VTail>(vtail)...) {}
template <typename VHead, typename... VTail, typename = std::enable_if_t<sizeof...(VTail)==sizeof...(Tail) > >
Tuple(Tuple<VHead, VTail...> const & other) : head(other.getHead()), tail(other.getTail()) {}
第二种:std::enable_if_t
为默认匿名 Nontype 模板参数
template <typename VHead, typename... VTail, std::enable_if_t<sizeof...(VTail)==sizeof...(Tail) > =0 >
Tuple(VHead&& vhead, VTail&&... vtail) : head(std::forward<VHead>(vhead)), tail(std::forward<VTail>(vtail)...) {}
template <typename VHead, typename... VTail, std::enable_if_t<sizeof...(VTail)==sizeof...(Tail) > =0 >
Tuple(Tuple<VHead, VTail...> const & other) : head(other.getHead()), tail(other.getTail()) {}
那么问题来了:
为什么加了相同的 enable_if 条件,就使得构造函数 2 的优先级比构造函数 1 的优先级高了呢(构造函数 1 、2 的条件都是 VTails 类型的个数和 Tail 的类型个数相同。
enable_if 的两种写法中第二种是CPP reference推荐写法, 原话是这么说的:A common mistake is to declare two function templates that differ only in their default template arguments. This does not work because the declarations are treated as redeclarations of the same function template (default template arguments are not accounted for in function template equivalence). 也就是说如果用第一种写法很可能会把构造函数 1 和构造函数 2 当成同一个函数声明和定义两次,当然本例中不存在这个问题,因为构造函数 1 和构造函数 2 在大部分情形下含有的参数个数不同,但至少这两种 enable_if 的写法是等价的。对于情形 1 构造相同模板参数 tuple 两种 enable_if 写法 gcc 和 msvc 均可以编译过去,但是对于情形 2 构造不同但可以相互转换的模板参数,只有第一种写法也就是默认模板参数方法,msvc 和 gcc 可以编译过去,这是为什么呢?
感谢您看完如此长的问题描述,谢谢!
编译器分别为 msvc 16.7 和 gcc 10
这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。
V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。
V2EX is a community of developers, designers and creative people.