问题描述
我正在尝试根据模板参数之一的类型为函数模板添加函数重载,并将定义为 consexpr 的参数传递到其他地方以帮助解决重载问题。
这是我要实现的目标的代码示例:
struct use_my_impl_t {};
constexpr use_my_impl_t use_my_impl;
template<
typename T,typename std::enable_if<std::is_same<T,use_my_impl_t>::value>::type * = nullptr>
void foo(int i,T&& t)
{
std::cout << "Using my impl: " << --i << std::endl;
}
template<
typename T,typename std::enable_if<!std::is_same<T,use_my_impl_t>::value>::type * = nullptr>
void foo(int i,T&& t)
{
std::cout << "Using default impl: " << ++i << std::endl;
}
因此,当我将 use_my_impl_t
的实例作为第二个参数传递时,它应该使用我的实现,对于所有其他情况,它应该使用默认实现。结果不是我所期望的。如果我这样调用:
constexpr use_my_impl_t use_my_impl;
foo(42,use_my_impl_t{});
foo(42,2);
foo(42,use_my_impl);
打印
Using my impl: 41
Using default impl: 43
Using default impl: 43
尽管传递了 use_my_impl_t
的实例,但为什么最后一条语句没有调用我的实现?
解决方法
这里的问题是 T
被推断为什么。在 foo(42,use_my_impl_t{});
中,use_my_impl_t{}
是一个右值,因此 T
被推导出为 use_my_impl_t
,参数变为 use_my_impl_t&&
。
对于 foo(42,use_my_impl);
,use_my_impl
是左值。这意味着 T
被推导出为 use_my_impl_t &
以保留该左值。这意味着参数变为 use_my_impl_t& &&
其中 collapses 到 use_my_impl_t&
。
这就是导致 std::is_same<T,use_my_impl_t>::value
不起作用的原因,因为 use_my_impl_t&
与 use_my_impl_t
不同。要解决此问题,您可以使用 std::decay_t
删除类型的引用和 cv 限定。那会给你
template<
typename T,typename std::enable_if<std::is_same<std::decay_t<T>,use_my_impl_t>::value>::type * = nullptr>
void foo(int i,T&& t)
{
std::cout << "Using my impl: " << --i << std::endl;
}
template<
typename T,typename std::enable_if<!std::is_same<std::decay_t<T>,use_my_impl_t>::value>::type * = nullptr>
void foo(int i,T&& t)
{
std::cout << "Using default impl: " << ++i << std::endl;
}
然后输出
Using my impl: 41
Using default impl: 43
Using my impl: 41
使用您的驱动程序代码。