针对 const char*、const char(&)[N] 和 std::string 的函数重载

4

我想要实现的是函数的重载功能,适用于字符串字面量和std::string,但对于const char*参数会产生编译时错误。以下代码几乎可以满足我的需求:

#include <iostream>
#include <string>

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

void foo(const std::string& str) {
    std::cout << "In overload for const std::string&     : " << str << std::endl;
}

template<size_t N>
void foo(const char (& str)[N]) {
    std::cout << "In overload for array with " << N << " elements : " << str << std::endl;
}   

int main() {
    const char* ptr = "ptr to const";
    const char* const c_ptr = "const ptr to const";
    const char arr[] = "const array";
    std::string cppStr = "cpp string";

    foo("String literal");
    //foo(ptr); //<- compile time error
    foo(c_ptr); //<- this should produce an error
    foo(arr);   //<- this ideally should also produce an error
    foo(cppStr);
}

我不是很满意它可以编译 char 数组变量,但如果我想接受字符串字面量的话,我认为没有其他办法(如果有,请告诉我)。

然而,我想避免的是 std::string 重载接受 const char * const 变量。不幸的是,我不能只声明一个删除的重载,该重载带有一个 const char * const& 参数,因为这也会匹配字符串字面量。

你有什么想法,如何使 foo(c_ptr) 产生编译时错误,而不影响其他重载?


字符数组和字符串字面量的类型是没有区别的,因此你不能丢掉其中任何一个。但我认为你的另一个要求是可以满足的。 - Tavian Barnes
@Tavian Barns:我在想,是否可以利用字符串字面值也是常量表达式这一事实(当然你也可以创建一个constexpr数组)。 - MikeMB
3个回答

4

这段代码可以完成所需的功能(除了数组 - 字面量本身就是数组,因此无法将它们分开)。

#include <cstddef>
#include <string>

template <class T>
void foo(const T* const & str) = delete;

void foo(const std::string& str);

template<std::size_t N>
void foo(const char (& str)[N]);

int main() {
    const char* ptr = "ptr to const";
    const char* const c_ptr = "const ptr to const";
    const char arr[] = "const array";
    std::string cppStr = "cpp string";

    foo("String literal");
    //foo(ptr); //<- compile time error
    // foo(c_ptr); //<- this should produce an error
    foo(arr);   //<- this ideally should also produce an error
    foo(cppStr);
}

谢谢。有了这个模板函数,我相信第一个重载(针对const char *& str)就不再必要了,对吗? - MikeMB

3
为了使删除函数不比模板函数更适配,以便字符串字面值仍然有效,删除函数也需要成为一个模板。这似乎满足您的要求(尽管数组仍然被允许):
template <typename T>
typename std::enable_if<std::is_same<std::decay_t<T>, const char*>::value>::type
foo(T&& str) = delete;

Demo.


...这就是我要做的,但你比我先完成了 :) - Tavian Barnes
这里不需要使用SFINAE。 - SergeyA
谢谢,我总是忘记那个。 - MikeMB

1
在现代版本的语言中,您可以创建一些自定义类型和用户定义的文字字面量来创建它,因此可以传递"this"_SOMEWORDS,而不仅仅是c字符串字面量、字符指针或字符数组。
它并不能完全满足您通过字符串字面量传递的要求,但我认为它已经足够好了,特别是因为它也禁止了数组。

这实际上是一个非常有趣的想法,因为它允许我们区分char数组和字符串字面量。但它并不能阻止std :: string重载接受const char * const参数。 - MikeMB
@MikeMB 现在直接删除它(const char*重载)就可以了。 - RiaD
抱歉,时间有点晚了。在编译时能否获取字符串字面量的长度(就像我的示例函数中的模板参数一样)? - MikeMB
@MikeMB,不幸的是我目前还没有成功做到。看起来模板形式只适用于整数/浮点字面量。 - RiaD
没问题,这不是一个难要求。再次感谢。到目前为止,我只在一些玩具示例中使用了用户定义的字面量,并且没有考虑过这个问题的方向。 - MikeMB

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接