gpt4 book ai didi

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

转载 作者:塔克拉玛干 更新时间:2023-11-03 00:23:25 26 4
gpt4 key购买 nike

考虑以下代码:

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/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com