orElse<v.get(),0>() 的意图已经够清楚了,但是如果这样的事情存在的话,
它必须是以下之一:
调用阵容
orElse(v,&V::get,0)
orElse<V,&V::get>(v,0)
orElse<V,&V::get,0>(v)
其中v 的类型为V,因此实例化了函数模板
分别是:
函数模板阵容
template<typename T>
int orElse(T & obj, int(T::pmf*)(), int deflt);
template<typename T, int(T::*)()>
int orElse(T & obj, int deflt);
template<typename T, int(T::*)(), int Default>
int orElse(T & obj);
正如您所理解的,没有这样的东西可以达到您想要的效果。
对于任何不明白这一点的人,
原因很简单:Invocation Lineup 中没有任何函数调用
如果没有 V::get 这样的成员,将编译。没有绕过去
那个,以及调用的函数可能是一个实例的事实
Function Template Lineup 中的函数模板没有任何区别。
如果V::get 不存在,那么任何提及它的代码都不会编译。
但是,您似乎有一个不需要实现的实际目标
以这种绝望的方式。看起来,对于给定名称 foo 和给定类型 R,
您希望能够只编写一个函数模板:
template<typename T, typename ...Args>
R foo(T && obj, Args &&... args);
这将返回R(T::foo) 的值,调用obj 并带有参数args...,
如果存在这样的成员函数,否则返回一些默认的R。
如果是的话,可以按照下图实现:
#include <utility>
#include <type_traits>
namespace detail {
template<typename T>
T default_ctor()
{
return T();
}
// SFINAE `R(T::get)` exists
template<typename T, typename R, R(Default)(), typename ...Args>
auto get_or_default(
T && obj,
Args &&... args) ->
std::enable_if_t<
std::is_same<R,decltype(obj.get(std::forward<Args>(args)...))
>::value,R>
{
return obj.get(std::forward<Args>(args)...);
}
// SFINAE `R(T::get)` does not exist
template<typename T, typename R, R(Default)(), typename ...Args>
R get_or_default(...)
{
return Default();
}
} //namespace detail
// This is your universal `int get(T,Args...)`
template<typename T, typename ...Args>
int get(T && obj, Args &&... args)
{
return detail::get_or_default<T&,int,detail::default_ctor>
(obj,std::forward<Args>(args)...);
}
// C++14, trivially adaptable for C++11
可以通过以下方式试用:
#include <iostream>
using namespace std;
struct A
{
A(){};
int get() {
return 1;
}
int get(int i) const {
return i + i;
}
};
struct B
{
double get() {
return 2.2;
}
double get(double d) {
return d * d;
}
};
struct C{};
int main()
{
A const aconst;
A a;
B b;
C c;
cout << get(aconst) << endl; // expect 0
cout << get(a) << endl; // expect 1
cout << get(b) << endl; // expect 0
cout << get(c) << endl; // expect 0
cout << get(a,1) << endl; // expect 2
cout << get(b,2,2) << endl; // expect 0
cout << get(c,3) << endl; // expect 0
cout << get(A(),2) << endl; // expect 4
cout << get(B(),2,2) << endl; // expect 0
cout << get(C(),3) << endl; // expect 0
return 0;
}
在复杂的返回类型中有“compound SFINAE”在起作用:
std::enable_if_t<
std::is_same<R,decltype(obj.get(std::forward<Args>(args)...))
>::value,R>
如果T::get 不存在则decltype(obj.get(std::forward<Args>(args)...)
不编译。但如果它编译了,T::get 的返回类型是
R 以外的东西,那么 std::enable_if_t 类型说明符不
编译。仅当成员函数存在并且具有所需的返回类型R
R(T::get) exists 案例可以实例化吗?否则
catch-all R(T::get) 不存在案例被选中。
注意get(aconst) 返回 0 而不是 1。应该是这样,
因为不能在 const A 上调用非常量重载 A::get()。
您可以对任何其他R foo(V & v,Args...) 和
存在或不存在R(V::foo)(Args...)。
如果R 不是默认可构造的,或者如果您想要默认的R
当 R(V::foo) 不存在时返回
R(),然后定义一个函数detail::fallback(或其他)返回
所需的默认 R 并指定它而不是 detail::default_ctor
如果您可以进一步模板参数化该模式,那该多好
适应T 的任何可能的成员函数和任何可能的返回
输入R。但是您需要的额外模板参数将
是R(T::*)(typename...),它的实例化值必须是
&V::get(或其他),然后模式将
迫使你陷入致命的陷阱,提及存在疑问的事物。