【问题标题】:How should one overload functions with const/non-const parameters?应该如何重载具有 const/non-const 参数的函数?
【发布时间】:2012-11-15 01:14:45
【问题描述】:

我有以下代码:

// string specializations
void foo(const char *a, const char *b);
void foo(const char *a, const std::string &b);
void foo(const std::string &a, const char *b);
void foo(const std::string &a, const std::string &b);

// generic implementation
template<typename TA, typename TB>
void foo(TA a, TA b)
{...}

问题在于这个测试用例:

char test[] = "test";
foo("test", test);

最终调用foo 的模板版本。显然,我可以使用非const 参数的各种混合添加更多重载,但我想知道:是否有更好的方法来重载foo,以便它专门针对所有const 和非const 成对的字符串?不需要我希望我没有错过一些参数类型的排列?

【问题讨论】:

  • char *test = "test" 不是你应该做的事情。 "test" const char*.
  • SFINAE 用于无法转换为 std::string 的类型,或者简单地制作 std::string 并要求调用者进行转换
  • 因为您错过了"test" 的类型为const char[5],而不是const char*
  • @jogojapan,从技术上讲,"test"const char[5]
  • 对不起,是的。当然,我的观点是const(转换为const char* 不是问题,而转换为char * 是临界的,只有在类型转换规则中不推荐使用的例外情况下才有可能)。跨度>

标签: c++ c++11 overloading


【解决方案1】:

感谢 Mooing Duck 的建议,这是我的解决方案:

// string specialization
void foo(const std::string &a, const std::string &b);

template<typename TA, typename TB>
typename std::enable_if<
    std::is_constructible<std::string, TA>::value &&
    std::is_constructible<std::string, TB>::value
>::type foo(TA a, TB b)
{
    foo(std::string(std::move(a)), std::string(std::move(b)));
}

// generic implementation
template<typename TA, typename TB>
typename std::enable_if<
    !std::is_constructible<std::string, TA>::value ||
    !std::is_constructible<std::string, TB>::value
>::type foo(TA a, TB b)
{...}

【讨论】:

  • 你只能std::forward Universal References
  • 我更喜欢std::is_convertible 而不是std::is_constructible,因为它还捕获std::string 的构造函数未实现的转换(如用户定义的隐式转换运算符)。
  • 在这里使用std::forward 并没有错,但在这种情况下,直接使用std::move 可能更直接,因为归根结底就是这样。
  • @ChristianRau std::is_constructible 将正确处理转换运算符。 std::is_constructible&lt;T, Arg&gt;::valuestd::is_convertible&lt;Arg, T&gt;::value 之间的区别(注意参数的顺序)是T t(std::declval&lt;Arg&gt;());T t = std::declval&lt;Arg&gt;(); 之间的区别。
  • @LucDanton 啊,感谢您的澄清(考虑到这一点,std::is_constructible 也捕获了转换运算符是有道理的)。事实上,std::is_constructible 似乎捕获的更多,因为 std::is_convertible 不会捕获显式构造函数。不确定这在这里是好是坏,但我想这在这种情况下是无关紧要的,因为无论如何调用foo(std::string::allocator_type(), ...) 可能不太可能。
【解决方案2】:

如果我正确理解您的目标,您可以这样做

template<typename T1,typename T2 >
void foo(T1, T2)
{
     static_assert(sizeof(T1) == 0,"Did not overload all foo's");
}

template<>
void foo<const char *a, const char *b>()
{
    ... Handle this case
}

... ect ect ect

这样做的好处是您可以明确地处理您想要的每个实例,同时如果您错过了一个会生成编译错误。

【讨论】:

  • 谢谢,但我只是使用 SFINAE 和字符串输入自己的答案(感谢 Mooing Duck)。
  • 这真的是一个解决方案吗?您仍然需要编写许多不同的专业。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2022-11-13
  • 2019-06-12
  • 1970-01-01
  • 2011-04-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多