为什么通用引用作为输入参数不起作用

Why universal reference as an input parameter doesn't work

提问人:f1msch 提问时间:6/23/2022 最后编辑:Evgf1msch 更新时间:6/23/2022 访问量:156

问:

template<typename T>
constexpr auto log_value(T&& value) {
    if constexpr (std::is_enum_v<T>) {
        cout << "enum" << endl;
    }
    else {
        cout << "normal" << endl;
    }
}

我有一个函数来判断某个值是否是枚举,我通过以下方式对其进行测试

enum class A {
    a,
    s,
    d
};

int main() {
    auto s = A::a;
    const auto& s1 = s;
    auto&& s2 = A::a;
    log_value(s);
    log_value(s1);
    log_value(s2);
    log_value(A::a);

但结果是

normal
normal
normal
enum

当我把它改成:

template<typename T>
constexpr auto log_value_const_left(const T& value) {
    if constexpr (std::is_enum_v<T>) {
        cout << "enum" << endl;
    }
    else {
        cout << "normal" << endl;
    }
}

它有效

enum
enum
enum
enum

现在我只是想知道为什么不起作用?输入参数中的输入参数不是可以引用左值引用或右值引用吗?log_valueT&& valuelog_value

如果在,它到底是什么?为什么它仍然被改变?std::is_enum_v<T> != truelog_value

C++ C++17 按引用传递 rvalue-reference

评论


答:

8赞 HolyBlackCat 6/23/2022 #1

转发(又称通用)引用对左值的工作方式是将引用类型(在您的情况下)推导为左值引用(在您的情况下)。然后也变成根据参考折叠规则 ( + = )。TA &T &&A &&&&&

对于右值,这不是必需的,并且被推导出为非引用。T

你想要。std::is_enum_v<std::remove_reference_t<T>>

评论

0赞 f1msch 6/23/2022
哇~~ 但是为什么(以左值引用为指向)不起作用?[en.cppreference.com/w/cpp/types/is_enum]似乎没有提到它。std::is_enum_v<T>
1赞 HolyBlackCat 6/23/2022
@f1msch 因为那是引用而不是枚举?通常,这些特征会忽略 cv 限定符(即 const 和 volatile),但不会忽略 reference-ness。is_...
0赞 Prof. 6/23/2022 #2

如果您使用 std::forward,则可以使用您的第一个版本。

enum class A {
  a,
  s,
  d
};

int main() {
    auto s = A::a;
    const auto& s1 = s;
    auto&& s2 = A::a;
    log_value(std::move(s));
    log_value(std::move(s1));
    log_value(std::move(s2));
    log_value(A::a);
}

但是 std::remove_reference_t 或 c++20 中的 std::remove_cvref 是你要走的路。