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

时间:2018-04-02 14:54:48

标签: c++ traits

你可能会说我应该没事了

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.

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

这样的东西
f(std::string("some literal")); 

也不是解决方案。

2 个答案:

答案 0 :(得分:1)

字符串文字不是 完全 a 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;
}

答案 1 :(得分:1)

A string literal is an lvalue。所以你不能只将字符串文字视为rvalues,而这并不是你想要的 - 你想要排除字符串文字。

这样做的一种方法是删除右值const char*重载:

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

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

调用foo("wat")更喜欢第二个(见this question),所以这实际上排除了它们(虽然字符串文字本身是一个左值,它衰变的指针是一个右值 - 所以它可以绑定到右值参考)。

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

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

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

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