带有默认参数的函数的c++部分排序
C++ partial ordering for a function with default argument
考虑以下代码:
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在特定情况下强制选择特定的候选对象(这里,在T
左值中存在一个可调用实体foo
,没有参数)。这里到底发生了什么?
具有void_t
的模板是为struct A
定义的,因此在调用时,您有两个有效的重载解析候选项。如果您想使用SFINAE,您必须确保对于任何给定的调用只有一个过载可用。要做到这一点,您应该首先将您的测试嵌入到类型特征中。为此,您可以以Yakk的can_apply
设施为例,我在这里无耻地复制它,因为它非常适合您的需求:
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>;
现在我们只需要在模板定义中使用上面定义的trait:
// 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上看到一个运行的例子
通常的方法之一是创建一个同样专门化的模板的分离。
#include <utility>
#include <iostream>
template<class T>
struct has_foo_impl
{
template<class U> static auto test(U* p) -> decltype(p->foo(), void(), std::true_type());
static auto test(...) -> decltype(std::false_type());
using type = decltype(test((T*)nullptr));
};
template<class T> using has_foo = typename has_foo_impl<T>::type;
template <class...>
using void_t = void;
template <class T, std::enable_if_t<not has_foo<T>::value>* = nullptr>
void bar(T){
std::cout << "not men";
}
template <class T, std::enable_if_t<has_foo<T>::value>* = nullptr>
void bar(T) {
std::cout << "men";
}
struct A { void foo(); } a;
int main()
{
bar(a); // "me"
}
没有一个函数比更专门化。
无论如何,你可以强制选择使用两个重载函数,如下所示:#include<utility>
template <class T>
void bar(char, T){}
template <class T>
auto bar(int, T) -> decltype(std::declval<T>().foo(), void()) {}
struct A { void foo(); } a;
int main() {
bar(0, a);
}
如果0
是int
,则先尝试bar(int, T)
。由于sfinae的原因,如果T
没有foo
成员函数,它可能被丢弃。无论如何,0
可以强制转换为char
,因此在这种情况下选择bar(char, T)
。
如果碰巧这两个函数都是可行的解决方案,则调用bar(int, T)
,因为它不需要任何隐式强制转换,并且调用不再有歧义。
这是另一个使用g++编译的解决方案:
//g++ 4.9.3
#include <iostream>
template <class T>
void bar(T)
{std::cout << "not foo boo...n";}
template <class T >
void bar( decltype(std::declval<T>().foo(),T()))
{std::cout << "foon";}
template <class T >
void bar( decltype(std::declval<T>().boo(),T()))
{std::cout << "boon";}
struct Foo { void foo(); } f;
struct Boo {void boo(); } b;
struct NotFooBoo { } n;
template <class T>
auto func(T&& t)
{
return bar<typename std::decay<T>::type>(std::forward<T>(t));
}
int main()
{
func(f);
func(b);
func(n);
}
因为你使用的是重载函数的默认值,所以编译器不知道你想使用哪个函数。
void bar(T, void_t<decltype(std::declval<T>().foo())>* = 0)
没有= 0
可以正常工作。
/编辑
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())>*)
{}
struct A
{
void foo();
} a;
int main()
{
bar(a);
return 0;
}
它的工作原理。
The program '[7464] Project3.exe' has exited with code 0 (0x0).
相关文章:
- 二叉排序树无法编译
- 仅使用绝对值对数组进行排序,并在C++中显示实际值
- C++选择排序算法中的逻辑错误
- 使用C++程序合并排序没有得到正确的输出
- 计算排序向量的向量中唯一值的计数
- 排序算法c++
- 使用2个键的cpp-stl::优先级队列排序不正确
- 将结构向量排序为子组
- 在c++中尝试对对象数组进行排序时,出现std:bad_alloc错误
- 如何对点云数据进行排序
- 对字符串进行排序时,在c++中处理sort()
- 是否有类似std::lower_bound的函数,而不需要排序/分区输入
- 下面是排序算法O(n)吗
- std::sort()函数无法对向量的一部分进行排序
- shell排序中的交换和比较
- clang格式:禁用排序包含
- 显示错误输出的简单数组排序程序
- 为什么我的排序算法会更改数组值
- 试图在c++中对数字列表进行排序
- 如何在C++中对数组进行冒泡排序