std::is_convertible 中的 std::decay 是多余的吗?

问题描述 投票:0回答:1

我写了这样的代码:

template <class T>
class A {
  template <class U, class = 
class std::enable_if_t<std::is_convertible_v<std::decay_t<U>, std::decay_t<T>>>>
      void f(U&& val) {}
    };

我希望我的班级的用户只能使用可转换为

f
的类型来调用
T

std::decay
是多余的吗?如果我删除它,也许我会错过一些特殊情况?

c++ c++17 enable-if perfect-forwarding
1个回答
2
投票

我认为你的问题更具哲学性,例如:在 C++ 类型的宇宙中,是否存在 T 和 U 的情况,在以下类上调用 f() 和 g() 之间存在可观察到的差异:

template <class T>
struct A {
 
    template <
        class U, 
        enable_if_t<is_convertible_v<decay_t<U>, decay_t<T>>>* = nullptr
    >
    void f(U&& val) {}

    template <
        class U, 
        enable_if_t<is_convertible_v<U, T>>* = nullptr
    >
    void g(U&& val) {}
};

decay_t 实际上做了什么?

  • 删除顶级 const/易失性限定符
  • 删除顶级参考限定符
  • 数组->指针转换
  • 函数->函数指针转换

可能值得注意的是:decay_t 是根据函数参数类型传递到函数时发生的情况建模的。

(已更新)

如果

U
按值取,则
decay_t<U>
将等于 U。

但是由于

U
是通用引用(在您的示例中),因此 U 可能会推断出引用类型,因此衰减它会产生可见的效果。当
T
只能从参考构造时,那么衰减它就会改变这种类型特征的答案。

Merry 的优秀例子:

#include <type_traits> #include <utility> template <class T> struct A { template < class U, std::enable_if_t<std::is_convertible_v<std::decay_t<U>, T>>* = nullptr > void f(U&& val) {} template < class U, std::enable_if_t<std::is_convertible_v<U, T>>* = nullptr > void g(U&& val) {} }; struct B { B(int &) {} }; void foo() {} int main() { A<B> a1; int x = 3; // a1.f(x); // fails to compile: int not convertible to B a1.g(x); // ok; int& is convertible to B }
    
© www.soinside.com 2019 - 2024. All rights reserved.