简体   繁体   English

使用通用引用进行重载分辨率

[英]Overload resolution with universal references

I have a function which can accept any type by universal reference, and would like to overload it for specific types (some of which are templated themselves, although I don't think that's important here). 我有一个函数,可以通过通用引用接受任何类型,并希望为特定类型重载它(其中一些是自己模板化的,虽然我不认为这在这里很重要)。 Unfortunately I can't quite seem to to get the overloads to be resolved in the right order. 不幸的是,我似乎无法以正确的顺序解决重载问题。

I would have presumed that the second declaration of foo would be preferred as it's more specific (less templated), although it looks like my understanding of overload resolution is lacking somewhat. 我会假设foo的第二个声明会更受欢迎,因为它更具体(模板化程度更低),尽管看起来我对重载决策的理解有些缺乏。 Interestingly changing the second declaration to take X by value makes it print "good, good" and making it take X by non-const reference makes it print "bad, good". 有趣的是改变第二个声明把X的值,使得其打印“好,好”,把它带到X通过非const引用使得其打印“坏,好”。 Obviously removing the first declaration entirely makes it return "good, good", as there's no other choice. 显然,删除第一个声明会使它返回“好,好”,因为没有其他选择。

So why does this happen? 那么为什么会这样呢? And most importantly, if the following code doesn't work, how can you overload a function with this signature? 最重要的是,如果以下代码不起作用,如何使用此签名重载函数?

#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;
}

Edit: 编辑:

Maybe a more roundabout solution to this is to do it indirectly. 也许更迂回的解决方案是间接地做到这一点。 Get rid of the first form of foo and use SFINAE to check if a valid overload exists, it it doesn't then call foo_fallback . 摆脱foo的第一种形式并使用SFINAE检查是否存在有效的过载,然后它不会调用foo_fallback

Xconst X的转换被认为比模板化过载与T = XT = X &的直接匹配更差。

To answer your question.comment to Kerre's answer, you could try to use SFINAE: 要回答您对于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!";
}

You'd have to implement a function fooImpl for any type that you don't want to be handled genericly. 你必须要实现的功能fooImpl用于任何类型的,你不想来处理genericly。

The implementation was a bit tricky, I tried just enable_if<is_same<string, decltype(fooImpl(declval<C>()))>::value first, but for the fallback the !is_same<>::value gave me compiler errors, because it tried to instantiate the decltype as well. 实现有点棘手,我首先尝试了enable_if<is_same<string, decltype(fooImpl(declval<C>()))>::value ,但对于回退, !is_same<>::value给了我编译器错误,因为它也试图实例化decltype。

This implementation has one caveat that you might or might not want to use: if T is convertible to some other type that has a fooImpl defined, that conversion will kick in. 这个实现有一个警告,你可能想要或可能不想使用:如果T可以转换为其他一个定义了fooImpl类型,那么转换就会启动。

You can see the whole thing in action here: http://ideone.com/3Tjtvj 你可以在这里看到整个事情: http//ideone.com/3Tjtvj

Update: if you don't want to allow type conversions, it actually gets easier: 更新:如果您不想允许类型转换,它实际上变得更容易:

#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!";
}

See http://ideone.com/miaoop http://ideone.com/miaoop

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM