Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/156.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 调用成员函数(如果存在),返回自由函数,反之亦然_C++_C++11_Sfinae - Fatal编程技术网

C++ 调用成员函数(如果存在),返回自由函数,反之亦然

C++ 调用成员函数(如果存在),返回自由函数,反之亦然,c++,c++11,sfinae,C++,C++11,Sfinae,如果成员函数foo存在于T上,并且没有调用自由函数foo(T)(如果两者都不存在,则编译失败),我是否可以编写一个模板函数,并使用参数T调用成员函数foo 比如: template<typename T> int call_foo(T t) { // if T::foo() exists return t.foo(); // else return foo(t); } 模板 int call_foo(T){ //如果T::foo()存在 返回t.foo(); //否则返回f

如果成员函数
foo
存在于
T
上,并且没有调用自由函数
foo(T)
(如果两者都不存在,则编译失败),我是否可以编写一个模板函数,并使用参数T调用成员函数
foo

比如:

template<typename T>
int call_foo(T t) {
// if T::foo() exists
    return t.foo();
// else return foo(t);
}
模板
int call_foo(T){
//如果T::foo()存在
返回t.foo();
//否则返回foo(t);
}

相反的情况如何:在成员函数之前优先选择自由函数
foo
?我不能使用C++11之后引入的任何功能。

这并不难。有许多方法可以检查任意表达式是否有效。您可以将其与C++17中的if constexpr或更早的标记分派相结合,以获得所需的行为

这将使用C++17,但所有操作都可以在以前的版本中完成:

#include <type_traits>
#include <utility>

// This is just one way to write a type trait, it's not necessarily
// the best way. You could use the Detection Idiom, for example
// (http://en.cppreference.com/w/cpp/experimental/is_detected).
template <typename T, typename = void>
struct has_member_fn
    : std::false_type
{};

// std::void_t is a C++17 library feature. It can be replaced
// with your own implementation of void_t, or often by making the
// decltype expression void, whether by casting or by comma operator
// (`decltype(expr, void())`)
template <typename T>
struct has_member_fn<T,
    std::void_t<decltype(std::declval<T>().foo())>>
    : std::true_type
{};


template <typename T, typename = void>
struct has_free_fn
    : std::false_type
{};

template <typename T>
struct has_free_fn<T,
    // Be wary of ADL. You're basically asking the compiler,
    // "What's the result of foo(T{}) if I were to call that
    // here?" That syntax can call functions via ADL
    std::void_t<decltype(foo(std::declval<T>()))>>
    : std::true_type
{};


template <typename T>
int call_foo(T t) {
    // if constexpr is C++17, but you can use tag dispatch to
    // do the same in prior versions
    if constexpr (has_member_fn<T>::value) {
        return t.foo();
    } else {
        // you could make this an `else if constexpr (has_free_fn<T>::value)`
        // and provide a better case for if neither exists
        return foo(t);
    }
}
#包括
#包括
//这只是编写类型特征的一种方法,不一定
//最好的办法。例如,您可以使用检测习惯用法
// (http://en.cppreference.com/w/cpp/experimental/is_detected).
模板
结构具有\u成员\u fn
:std::false\u类型
{};
//void\t是一个C++17库特性。它可以被替换
//使用您自己的void\u t实现,或者通常通过
//decltype表达式无效,无论是通过强制转换还是通过逗号运算符
//(`decltype(expr,void())`)
模板
结构具有\u成员\u fn
:std::true\u类型
{};
模板
结构有_free _fn
:std::false\u类型
{};
模板

struct在C++17之前有\u free\u fn,如果constexpr
,则可以使用
编译/不编译同一函数的不同部分

因此,在C++17之前,您必须在某个地方执行两个不同的函数

举个例子:如果你准备了几个助手函数

template <typename T>
auto call_foo_h (T t, int) -> decltype( t.foo() )
 { return t.foo(); }

template <typename T>
auto call_foo_h (T t, long) -> decltype( foo(t) )
 { return foo(t); }
观察
call_foo_h()
中的第二个(未使用)参数;
T::foo()
版本中的
int
,自由版本中的
long

这里有一个技巧:使用
int
0
)调用
call\u foo\u h
),如果可用,最好调用
int
版本(
T::foo()
),否则调用
long
版本

相反的情况如何:在成员函数之前优先选择自由函数
foo

在这种情况下,编写
调用\u foo()
,如下所示

template <typename T>
int call_foo (T const & t)
 { return call_foo_h(t, 0); }
//......................^ a int value
template <typename T>
int call_foo (T const & t)
 { return call_foo_h(t, 0L); }
//......................^^ a long value
模板
int call_foo(T const&T)
{返回调用_foo_h(t,0L);}
//长期价值

也就是说:使用
long
值调用
call\u foo\u h
,优先于免费
foo()
版本。

您可以(可能不是最好的链接)。对免费函数不是很确定。@Justin-两个答案都不错,但我没有马上接受,因为我没有尝试过,然后就忘了!我现在接受了一个C++11解决方案,因为这是我要求的,而另一个依赖于更新的特性。谢谢你的戳!我接受了这个答案,但如果您使用C++17或更高版本,也值得一看。@BeeOnRope-我同意:我对另一个答案投了赞成票。这个解决方案通常对我有效,但我的逻辑颠倒了,因此首先执行自由函数查找。但是,如果在has\u free方法之前没有定义free函数,has\u free将失败,即使在调用call\u foo之前定义了free函数也是如此。这是MSDEV2019。有什么见解吗?我承认这种行为在call_foo和call_foo之间是不同的。我不知道内置是否给我带来了麻烦。@Steven我不知道什么是MSDEV2019,但如果你能使用C++20,那么使用概念就最容易了。类似于
的东西需要(T){foo(T);}
。否则,我想用一个具体的例子来获得你想要的行为。如果你想问另一个关于这个变化的问题,也许这是合适的。我不介意你给我一个链接到上述问题,但不管怎样,你可能会得到很好的答案。