使用constexpr,SFINAE和/或type_traits

时间:2019-06-05 21:20:11

标签: c++ overloading sfinae typetraits enable-if

我遇到了一个有趣的挑战,我已经尝试解决了几个小时,但是经过大量研究和许多失败的尝试,我发现自己在问这个问题。

我想编写3个重载函数,每个重载函数均采用以下类型之一:const char*const char(&)[N]string literal (e.g. "BOO")。我知道字符串文字只是一个char数组,但是在解释我的方法时请耐心等待。

由于包装器类const char*,下面的两个函数能够区分前两种类型(const char(&)[N]CharPtrWrapper):

#include <iostream>

class CharPtrWrapper
{
public:
    CharPtrWrapper(const char* charPtr)
        : m_charPtr(charPtr)
    {

    }

    const char * m_charPtr;
};

void processStr(CharPtrWrapper charPtrWrapper)
{
    std::cout << "From function that takes a CharPtrWrapper = " << charPtrWrapper.m_charPtr << '\n';
}

template<std::size_t N>
void processStr(const char (&charArr)[N])
{
    std::cout << "From function that takes a \"const char(&)[N]\" = " << charArr << '\n';
}

int main()
{
    const char* charPtr = "ABC";
    processStr(charPtr);

    const char charArr[] = {'X', 'Y', 'Z', '\0'};
    processStr(charArr);
}

输出:

From function that takes a CharPtrWrapper = ABC
From function that takes a "const char(&)[N]" = XYZ

现在,如果我使用字符串文字(例如processStr)调用processStr("BOO"),则将调用采用const char(&)[N]的版本,这很有意义,因为字符串文字只是一个字符数组。

这是我解决问题的关键所在。我无法编写一个能够区分char数组和字符串文字的函数。我认为可能有用的一件事是编写一个带有右值引用的版本:

template<std::size_t N>
void processStr(const char (&&charArr)[N])
{
    std::cout << "From function that takes a \"const char(&&)[N]\" = " << charArr << '\n';
}

但是事实证明,字符串文字是左值。我还玩过使用std::enable_ifstd::is_array的不同版本,但仍然没有得到想要的结果。

所以我想我的问题是:在现代C ++中可以区分char数组和字符串文字吗?

1 个答案:

答案 0 :(得分:2)

[expr.prim.id.unqual]

  

[...]表达式的类型是标识符的类型。的   结果是由 identifier 表示的实体。表达式是   如果实体是一个函数,变量或数据成员,并且一个   prvalue否则;如果标识符指定一个位,则为位字段   位字段([dcl.struct.bind])。

因此,给出了声明

const char arr[] = "foo";

表达式arr是类型const char[4]的左值。


[lex.string]/8

  

还引用了普通字符串文字和UTF-8字符串文字   作为狭窄的字符串文字。窄字符串文字的类型为“数组   的 n const char”,其中 n 是定义的字符串大小   下方,并且具有静态存储期限。

并且根据[expr.prim.literal]

  

litera 是主要表达。其类型取决于其形式。一种   字符串文字是左值;所有其他文字都是prvalue。

因此,表达式"foo"是类型const char[4]的左值。


结论:函数无法区分(const)char数组和字符串文字。