使用 constexpr、SFINAE and/or type_traits 对 char*、char 数组和字符串文字的重载解析

Overload resolution for char*, char array, and string literals using constexpr, SFINAE and/or type_traits

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

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

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

#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', '[=12=]'};
    processStr(charArr);
}

输出:

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

现在,如果我用字符串文字(例如 processStr("BOO"))调用 processStr,将调用采用 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++ 中是否可以区分字符数组和字符串文字?

根据 [expr.prim.id.unqual]:

[...] The type of the expression is the type of the identifier. The result is the entity denoted by the identifier. The expression is an lvalue if the entity is a function, variable, or data member and a prvalue otherwise; it is a bit-field if the identifier designates a bit-field ([dcl.struct.bind]).

因此,给定一个声明

const char arr[] = "foo";

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


根据 [lex.string]/8:

Ordinary string literals and UTF-8 string literals are also referred to as narrow string literals. A narrow string literal has type “array of n const char”, where n is the size of the string as defined below, and has static storage duration.

根据 [expr.prim.literal]:

A litera is a primary expression. Its type depends on its form. A string literal is an lvalue; all other literals are prvalues.

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


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