如果foo
上存在成员函数T
,并且如果它不调用自由函数foo(T)
,我可以编写一个模板函数来调用成员函数template<typename T>
int call_foo(T t) {
// if T::foo() exists
return t.foo();
// else return foo(t);
}
吗?如果两者都不存在则无法编译?
类似的东西:
foo
相反的情况怎么样:在成员函数之前更喜欢自由函数export class ServerCertificationGrid implements OnInit {
public data: GridDataResult;
private filter: CompositeFilterDescriptor;
public state: DataSourceRequestState = {
skip: 0,
take: 20,
filter: filterBy(this.data, { // This also does not work.
logic: 'and',
filters: [
{ field: "name", operator: "contains", value: this.applicationName, ignoreCase: true }
]
})
};
@Input() public applicationName: string;
constructor(private dataService: DataService, private dialogService: DialogService) {
console.log(this.applicationName);
// This does not work because this.state.filter is null.
//let fd: FilterDescriptor = {
// field: "name",
// operator: "contains",
// value: this.applicationName,
// ignoreCase: true
//}
//this.state.filter.filters.push(fd);
this.dataService.getCertificationOverview(this.state)
.subscribe(r => {
console.log(r);
this.data = r;
});
}
?我不能使用C ++ 11之后引入的任何功能。
答案 0 :(得分:14)
这不太难。有许多方法可以检查任意表达式是否有效。您可以将其与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);
}
}
答案 1 :(得分:6)
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); }
只有T::foo()
存在(第一个)或者存在免费foo()
(第二个)时才启用SFINAE,您可以按如下方式编写call_foo()
template <typename T>
int call_foo (T const & t)
{ return call_foo_h(t, 0); }
//......................^ a int value
观察call_foo_h()
中的第二个(未使用的)参数; int
版本中的T::foo()
,免费版本中的long
。
以下是诀窍:使用call_foo_h
(int
)调用0
,您可以调用int
版本(T::foo()
),如果可用,和long
版本。
相反的情况怎么样:在成员函数之前更喜欢自由函数
foo
?
在这种情况下,请按以下方式编写call_foo()
template <typename T>
int call_foo (T const & t)
{ return call_foo_h(t, 0L); }
//......................^^ a long value
即:使用call_foo_h
值调用long
,优先考虑免费foo()
版本。