8

我有一个可以通过通用引用接受任何类型的函数,并且想为特定类型重载它(其中一些是自己模板化的,尽管我认为这在这里并不重要)。不幸的是,我似乎无法以正确的顺序解决重载问题。

我会认为第二个声明foo会更受欢迎,因为它更具体(更少模板化),尽管看起来我对重载决议的理解有些缺乏。有趣的是,将第二个声明更改为X按值获取使其打印“好,好”,并使其X通过非常量引用使其打印“坏,好”。显然,完全删除第一个声明会使其返回“好,好”,因为没有其他选择。

那么为什么会这样呢?最重要的是,如果下面的代码不起作用,你怎么能用这个签名重载一个函数呢?

#include <iostream>
#include <string>

class X {};

template<typename T>
inline std::string foo(T && rhs) {
    return "bad";
}

inline std::string foo(const X & rhs) {
    return "good";
}

int main() {
    std::cout << foo(X()) << std::endl;
    X x;
    std::cout << foo(x) << std::endl;
    return 0;
}

编辑:

也许一个更迂回的解决方案是间接地做到这一点。摆脱第一种形式foo并使用 SFINAE 检查是否存在有效的重载,然后它不会调用foo_fallback.

4

2 回答 2

4

Xto的转换const X被认为比模板化重载与T = Xor的直接匹配更差T = X &

于 2013-05-22T14:53:39.287 回答
4

要回答您对 Kerre 的问题的评论,您可以尝试使用 SFINAE:

#include <type_traits>
#include <string>

template <class T>
struct HasFooImpl_ {
  template <typename C>
  static std::true_type test(decltype(fooImpl(std::declval<C>()))*);
  template <typename C> 
  static std::false_type test(...);
  typedef decltype(test<T>(0)) type;
};

template <typename T>
using HasFooImpl = typename HasFooImpl_<T>::type;

template <typename T>
typename std::enable_if<HasFooImpl<T>::value, std::string>::type 
foo(T&& t)
{
  return fooImpl(std::forward<T>(t));
}

template <typename T>
typename std::enable_if<!HasFooImpl<T>::value, std::string>::type
foo(T&& t)
{
    return "generic!";
}

您必须为fooImpl您不想被一般处理的任何类型实现一个函数。

实现有点棘手,我只是enable_if<is_same<string, decltype(fooImpl(declval<C>()))>::value先尝试​​过,但是对于回退,!is_same<>::value它给了我编译器错误,因为它也尝试实例化 decltype。

这个实现有一个你可能想或不想使用的警告:如果T转换为具有fooImpl定义的其他类型,则该转换将启动。

你可以在这里看到整个事情:http: //ideone.com/3Tjtvj

更新: 如果您不想允许类型转换,它实际上变得更容易:

#include <type_traits>
#include <string>

template <typename T> void fooImpl(T);

template <typename T>
using HasFooImpl = typename std::is_same<std::string, decltype(fooImpl(std::declval<T>()))>;

template <typename T>
typename std::enable_if<HasFooImpl<T>::value, std::string>::type 
foo(T&& t)
{
  return fooImpl(std::forward<T>(t));
}

template <typename T>
typename std::enable_if<!HasFooImpl<T>::value, std::string>::type
foo(T&& t)
{
    return "generic!";
}

http://ideone.com/miaoop

于 2013-05-22T16:02:55.873 回答