Fra*_*ank 5 c++ templates sfinae
可能重复:
是否可以编写C ++模板来检查函数的存在?
我有一个f
接收val
类型T
(模板化)值的函数。val
仅当类型具有此类成员函数时,才可以使用任何方法来调用该成员函数吗?
例:
struct Bar {
void foo() const {}
};
template<class T>
void f(T const& val) {
// Is there any way to call *only* if foo() is available on type T?
// SFINAE technique?
val.foo();
}
int main() {
Bar bar;
f(bar);
f(3.14);
}
Run Code Online (Sandbox Code Playgroud)
在我看来,这听起来像是SFINAE技术,也许使用boost :: enable_if,但是我不知道如何在这里使它工作。请注意,我无法轻松更改Bar
示例中的类型。我知道,如果Bar
包含某些特定的typedef等会很容易,这表明该功能可用。
不用说,我不知道类型的集合T
是f
将被调用。有些具有foo
成员函数,有些则没有。
您可以按照下面的测试程序(使用 GCC 4.7.0 或 clang 3.1 构建)所示执行此操作。
如果该方法存在并且是公共的,则静态模板函数has_void_foo_no_args_const<T>::eval(T const & t)
将被调用。如果没有这样的方法,它什么也做不了。(当然,如果该方法是私有的,则会导致编译错误。)t.foo()
void T::foo() const
这个解决方案是从我在这里贡献的方法内省模板改编和扩展的。您可以阅读该答案以了解 SNIFAE 逻辑如何工作的解释,还可以了解如何推广该技术以参数化您正在探测的函数签名的属性。
#include <iostream>
/*! The template `has_void_foo_no_args_const<T>` exports a
boolean constant `value` that is true iff `T` provides
`void foo() const`
It also provides `static void eval(T const & t)`, which
invokes void `T::foo() const` upon `t` if such a public member
function exists and is a no-op if there is no such member.
*/
template< typename T>
struct has_void_foo_no_args_const
{
/* SFINAE foo-has-correct-sig :) */
template<typename A>
static std::true_type test(void (A::*)() const) {
return std::true_type();
}
/* SFINAE foo-exists :) */
template <typename A>
static decltype(test(&A::foo))
test(decltype(&A::foo),void *) {
/* foo exists. What about sig? */
typedef decltype(test(&A::foo)) return_type;
return return_type();
}
/* SFINAE game over :( */
template<typename A>
static std::false_type test(...) {
return std::false_type();
}
/* This will be either `std::true_type` or `std::false_type` */
typedef decltype(test<T>(0,0)) type;
static const bool value = type::value; /* Which is it? */
/* `eval(T const &,std::true_type)`
delegates to `T::foo()` when `type` == `std::true_type`
*/
static void eval(T const & t, std::true_type) {
t.foo();
}
/* `eval(...)` is a no-op for otherwise unmatched arguments */
static void eval(...){
// This output for demo purposes. Delete
std::cout << "T::foo() not called" << std::endl;
}
/* `eval(T const & t)` delegates to :-
- `eval(t,type()` when `type` == `std::true_type`
- `eval(...)` otherwise
*/
static void eval(T const & t) {
eval(t,type());
}
};
// For testing
struct AA {
void foo() const {
std::cout << "AA::foo() called" << std::endl;
}
};
// For testing
struct BB {
void foo() {
std::cout << "BB::foo() called" << std::endl;
}
};
// For testing
struct CC {
int foo() const {
std::cout << "CC::foo() called" << std::endl;
return 0;
}
};
// This is the desired implementation of `void f(T const& val)`
template<class T>
void f(T const& val) {
has_void_foo_no_args_const<T>::eval(val);
}
int main() {
AA aa;
std::cout << (has_void_foo_no_args_const<AA>::value ?
"AA has void foo() const" : "AA does not have void foo() const")
<< std::endl;
f(aa);
BB bb;
std::cout << (has_void_foo_no_args_const<BB>::value ?
"BB has void foo() const" : "BB does not have void foo() const")
<< std::endl;
f(bb);
CC cc;
std::cout << (has_void_foo_no_args_const<CC>::value ?
"CC has void foo() const" : "CC does not have void foo() const")
<< std::endl;
f(cc);
std::cout << (has_void_foo_no_args_const<double>::value ?
"Double has void foo() const" : "Double does not have void foo() const")
<< std::endl;
f(3.14);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
该程序输出:
AA has void foo() const
AA::foo() called
BB does not have void foo() const
T::foo() not called
CC does not have void foo() const
T::foo() not called
Double does not have void foo() const
T::foo() not called
Run Code Online (Sandbox Code Playgroud)
如果你有一个typedef bool has_f
, 或一个 static (在编译时可用的东西),我想你可以分支(使用 boost 元编程函数),或者提供 2 个模板,一个模板如果定义了则实例化has_f
另一个模板,如果没有定义则实例化另一个模板。恕我直言,如果没有关于 的元数据,它感觉不直接可行T
。
归档时间: |
|
查看次数: |
6023 次 |
最近记录: |