检查 T 是否为左值的特征,不包括字符串文字

Traits to check whether T is an lvalue, excluding string literals

你可能会说我应该没问题

std::is_lvalue_reference<T>::value 

但是当字符串文字出现在问题中时,问题就出现了。正如我所读到的,字符串文字被视为 const char*,它被评估为左值。如何确保将字符串文字视为右值?

假设以下代码不存在。

template <typename T>
inline static void f(T&& arg) {
    static_assert(my_lvalue_traits<T>::value, "Only lvalue permitted") ;
   // Some code.
}

如果我想达到这些结果,my_lvalue_traits 应该是什么样子?

std::string x;
f(x); // Everything OK, the argument is an lvalue. 

int y;
f(y); // Everything OK, the argument is an lvalue.

f("some literal"); // Static assertion failure. I want string literal to behave as an rvalue. 

f(5); // Static assertion failure. Argument is an rvalue.

请注意,我想在可变参数模板中使用这个特征 class,所以这可能不是一个完美的例子。像

f(std::string("some literal")); 

也不是解决方案。

字符串文字完全 const char *。您可以通过专业化来利用这一点。

使用 gcc 7.3.1 测试:

#include <type_traits>
#include <utility>
#include <functional>

template<typename T>
inline static void f(T&& arg) {
    static_assert(std::is_lvalue_reference_v<T>, "Only lvalue permitted");
}

template<size_t n>
inline static void f(const char (&arg)[n])
{
    static_assert(n!=n, "Only lvalue permitted");
}

int main()
{
    std::string x;

    f(x); // ok

    int y;

    f(y); // ok

    const char *p;

    f(p); // ok

    f("foobar"); // fail

    return 0;
}

A string literal is an lvalue。因此,您不能只将字符串文字视为右值,而这并不是您真正想要的 - 您想要排除字符串文字。

一种方法是删除右值 const char* 重载:

template <typename T>
void foo(T&& ) {
    static_assert(std::is_lvalue_reference_v<T>);
}

void foo(const char*&& ) = delete;

调用 foo("wat") 更喜欢第二个(参见 ),因此这有效地排除了它们(虽然字符串文字本身是一个左值,但它衰减到的指针是一个右值 - 所以它可以绑定到右值引用)。

但是,请注意,这也有效地排除了任何其他字符数组。

foo("hello"); // ill-formed, as desired

const char msg[] = "hello";
foo(msg); // also ill-formed, unfortunately

确实没有办法解决这个问题,因为您无法区分(编辑:在模板推导过程中的替换点)字符串文字和任何其他类型的字符数组。