我是否可以编写一个带有参数T的模板函数,foo如果它存在T,则调用成员函数,如果它不调用自由函数foo(T)(如果两者都不存在则无法编译)?
就像是:
template<typename T>
int call_foo(T t) {
// if T::foo() exists
return t.foo();
// else return foo(t);
}
Run Code Online (Sandbox Code Playgroud)
相反的情况怎么样:foo在成员函数之前更喜欢自由函数?我不能使用C++ 11之后引入的任何功能.
Jus*_*tin 15
这不是太难.有许多方法可以检查任意表达式是否有效.您可以将它与if constexpr早期的C++ 17或标签分发相结合,以获得您想要的行为.
这使用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);
}
}
Run Code Online (Sandbox Code Playgroud)
Pre C++ 17你可以编译/不编译同一个函数的不同部分if 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); }
Run Code Online (Sandbox Code Playgroud)
只有T::foo()存在(第一个)或者如果foo()存在空闲(第二个)时才启用SFINAE ,你可以写call_foo()如下
template <typename T>
int call_foo (T const & t)
{ return call_foo_h(t, 0); }
//......................^ a int value
Run Code Online (Sandbox Code Playgroud)
观察第二个(未使用的)参数call_foo_h(); 一个int在T::foo()版本,一个long免费版本.
这是诀窍:call_foo_h使用int(0)调用优选地调用int版本(the T::foo()),如果可用,则调用long版本.
相反的情况怎么样:
foo在成员函数之前更喜欢自由函数?
在这种情况下写call_foo()如下
template <typename T>
int call_foo (T const & t)
{ return call_foo_h(t, 0L); }
//......................^^ a long value
Run Code Online (Sandbox Code Playgroud)
即:call_foo_h使用long值调用,优先使用免费foo()版本.
| 归档时间: |
|
| 查看次数: |
1322 次 |
| 最近记录: |