具有默认参数的函数的 C++ 偏序

标签 c++ templates c++11

考虑以下代码:

template <class...>
using void_t = void;

template <class T>
void bar(T){}

template <class T>
void bar(T, void_t<decltype(std::declval<T>().foo())>* = 0) {}

struct A { void foo(); } a;
bar(a); // gives a compiler error on ambiguous call

那么问题来了,为什么这些重载会模棱两可?为什么编译器不认为第二个重载比第二个重载更严格、更专业?

最佳答案

您正在尝试使用 SFINAE 在特定情况下强制选择特定候选人(此处,可调用实体 foo 的存在在 T 中不带任何参数> 左值)。这里到底发生了什么?

带有 void_t 的模板是为您的 struct A 定义的,因此在调用时您有两个有效的重载决议候选者。如果你想使用 SFINAE,你必须确保对于任何给定的调用只有一个重载可用。为此,您应该首先将测试嵌入到类型特征中。为此,您可以在 Yakk's can_apply facility 上举个例子我无耻地复制在这里,因为它非常符合您的需要:

namespace details {
  // if Z<Ts...> is invalid, false_type:
  template <template<class...> class Z, class always_void, class... Ts>
  struct can_apply : std::false_type {};

  // if Z<Ts...> is valid, true_type:
  template <template<class...> class Z, class... Ts>
  struct can_apply<Z, std::void_t<Z<Ts...>>, Ts...> : std::true_type {};
}
// alias to inject the void type where we need it for SFINAE:
template <template<class...> class Z, class... Ts>
using can_apply = details::can_apply<Z, void, Ts...>;

template <typename T>
using has_foo_t = decltype(std::declval<T>().foo());

template <typename T>
using has_foo = can_apply<has_foo_t, T>;

现在我们只需要在我们的模板定义中使用上面定义的特征:

// The enable_if with the negation is needed to invalidate
// this implementation when T indeed has foo().
// This is what you were missing in your original idea.
template <typename T>
std::enable_if_t<!has_foo<T>::value> bar(T) {
    std::cout << "T has no foo(void)" << std::endl;
}

template <typename T>
std::enable_if_t<has_foo<T>::value> bar(T) {
    std::cout << "T has a foo(void)" << std::endl;
}

您可以在 Coliru 上看到一个运行示例.

关于具有默认参数的函数的 C++ 偏序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39489405/

相关文章:

c++ - 用 BFS 找路

c++ - 为什么更改 visual studio 版本后我的函数会崩溃?

c++ - 如何将assimp(断言导入器)交叉编译到ps4或XBox1等平台

c++ - 如何从 Alexandrescu A. 'Append' 编译模板类 "Modern C++ Design. Generic Programming and Design Patterns Applied"?

c++ - C 中的模板在 C++ 中使用 void *

c++ - 是否可以将 std::deque 的成员函数作为参数传递?

c++ - boost::variant 访问者返回错误(最烦人的解析?)

c++ - 是否有一个 lint 工具可以检查子类虚函数是否与父类定义匹配?

c++ - 用 vector 元素调用函数的通用模板

html - Liferay 7 Freemarker 模板。 staticUtil 已评估为 NULL 或缺失 - 尝试获取 JournalArticle 的类别