条款27:熟悉万能引用类型进行重载的替代方案

标签分派

一个万能引用形参通常会导致的后果是无论传入了什么都给出一个精确匹配结果,不过,如果万能引用仅是形参列表的一部分,该列表中还有其他非万能引用类型的形参的话,那么只要该非万能引用形参具备充分差的匹配能力,则它足以將这个带有万能引用形参的重载版本剔除出局。举例条款26的代码:

std::multiset<std::string> names;		// 全局数据结构
void logAndAdd(const std::string &name) {
	auto now = std::chrono::system_clock::now();
	log(now, "logAndAdd");
	names.emplace(name);				// 將名字添加到全局数据结构中
}

本条款的目的是避免条款26的问题,重新实现logAndAdd, 把它委托另外两个函数,一个接受整形数值,另一个接受其他所有类型。而logAndAdd本书则接受所有类型的实参:

template<typename T>
void logAndAdd(T &&name) {
    logAndAddImpl(std::forward<T>(name),
                  std::is_integeral<T>());	// 不够正确
}

上面这个函数把它的形参转发给了logAndAddImpl,但它还传递了另外一个实参,用来表示那个形参的类型T是否为整型;如果传递给万能应用name是个左值,那么T会推导为左值引用。这意味着std::is_intergral<T>在函数接受任意左值实参时,会得到结果“假”。std::remove_reference会移除类型所附的一切引用饰词:

template<typename T>
void logAndAdd(T &&name) {
    logAndAddImpl(std::forward<T>(name),
                  std::is_integral<typename std::remove_reference<T>::type>();
}

完成logAndAdd后我们再来实现logAndAddImpl。有连个重载版本,一个是只针对于非整型:

template<typename T>
void logAndAddImpl(T &&name, std::false_type) { // 非整型实参
    auto now = std::chrono::system_clock()::now();
    log(now, "logAndAdd");
    names.emplaces(std::forward<T>(name));
}

如果T是整型,则经由logAndAdd传递给logAndAddImpl的实参就会是一个继承自std::true_type的对象,反之,则会是std::false_type的对象。第二个重载包含了T是整型的相反情况:

std::string nameFromIdx(int dx);
void logAndAddImpl(T &&name, std::false_type) { // 整型实参
	logAndAdd(nemeFromIdx(idx));
}

上述设计中,类型std::false_typestd::true_type就是所谓的标签

对接受万能引用的模板施加限制

std::enable_if可以强制编译器表现出来的行为如同特定模板不存在一般。

class Person{
    template<typename T,
             typename = typename std::enbale_if<condition>::type>
    explicit Person(T &&n);
};

// 后续待补充。。。。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值