我已经阅读了有关这方面的各种权威,包括Dewhurst,但却未能通过这个看似简单的问题找到答案。
我想做的是调用一个C ++ function object,(基本上,你可以调用的任何东西,纯函数或带()的类,并返回它的值,如果这不是无效的,否则就是“真实的”。
using std:
struct Foo {
void operator()() { cout << "Foo/"l; }
};
struct Bar {
bool operator()() { cout << "Bar/"; return true; }
};
Foo foo;
Bar bar;
bool baz() { cout << "baz/"; return true; }
void bang() { cout << "bang/"; }
const char* print(bool b) { cout << b ? "true/" : "false/"; }
template <typename Functor> bool magicCallFunction(Functor f) {
return true; // Lots of template magic occurs here
// that results in the functor being called.
}
int main(int argc, char** argv) {
print(magicCallFunction(foo));
print(magicCallFunction(bar));
print(magicCallFunction(baz));
print(magicCallFunction(bang));
printf("\n");
}
// Results: Foo/true/Bar/true/baz/true/bang/true
更新
感谢您的想法和想法!
基于此,我实际上决定提出我所有的模板级别 - 所以我有:
bool eval(bool (*f)()) { return (*f)(); }
bool eval(void (*f)()) { (*f)(); return true; }
template <typename Type>
bool eval(Type* obj, bool (Type::*method)()) { return (obj->*method)(); }
template <typename Type>
bool eval(Type* obj, void (Type::*method)()) { (obj->*method)(); return true; }
和泛型类携带各种对象和方法。感谢Mr.Ree的代码推动了我朝这个方向发展!
答案 0 :(得分:6)
要在编译时检测void返回值,标准技巧是重载operator,
。逗号运算符很酷的是它可以采用void参数,在这种情况下,它默认为内置operator,
。在代码中:
template <typename> tag {};
template <typename T>
tag<T> operator,(T, tag<void>);
现在,expr, tag<void>()
的类型为tag<typeof(expr)>
,即使expr
的类型为void。然后你可以用常规技巧来捕捉这个:
char (&test(tag<void>))[1];
template <typename T> char (&test(tag<T>))[2];
template <typename F>
struct nullary_functor_traits
{
static const bool returns_void = sizeof(test((factory()(), tag<void>()))) == 1;
private:
static F factory();
};
答案 1 :(得分:1)
也许你可以使用void&amp;没有意义的类型,但无效*。
答案 2 :(得分:1)
实现 print(void)的重载无操作版本会不会更容易?
好吧,好吧。函数模板和重载将在运行时轻松处理。如果你想在编译时处理它,与#if宏或static-compile-time-asserts一起使用,它会变得有些棘手。
但是既然你只想要前者,我可以建议这样的东西作为起点:
(根据(GCC)3.4.4和4.0.1测试。 - 我知道,我需要升级!)
#include <iostream>
using namespace std;
struct Foo {
void operator()() {}
};
struct Bar {
bool operator()() { return false; }
};
Foo foo;
Bar bar;
bool baz() { return false; }
void bang() {}
struct IsVoid
{
typedef char YES[1];
typedef char NO[2];
/* Testing functions for void return value. */
template <typename T>
static IsVoid::NO & testFunction( T (*f)() );
static IsVoid::YES & testFunction( void (*f)() );
static IsVoid::NO & testFunction( ... );
/* Testing Objects for "void operator()()" void return value. */
template <typename C, void (C::*)()>
struct hasOperatorMethodStruct { };
template <typename C>
static YES & testMethod( hasOperatorMethodStruct<C, &C::operator()> * );
template <typename C>
static NO & testMethod( ... );
/* Function object method to call to perform test. */
template <typename T>
bool operator() (T & t)
{
return ( ( sizeof(IsVoid::testFunction(t)) == sizeof(IsVoid::YES) )
|| ( sizeof(IsVoid::testMethod<T>(0)) == sizeof(IsVoid::YES) ) );
}
};
#define BOUT(X) cout << # X " = " << boolToString(X) << endl;
const char * boolToString( int theBool )
{
switch ( theBool )
{
case true: return "true";
case false: return "false";
default: return "unknownvalue";
}
}
int main()
{
IsVoid i;
BOUT( IsVoid()(foo) );
BOUT( IsVoid()(bar) );
BOUT( IsVoid()(baz) );
BOUT( IsVoid()(bang) );
cout << endl;
BOUT( i(foo) );
BOUT( i(bar) );
BOUT( i(baz) );
BOUT( i(bang) );
}
好的,我开始看到更多问题。
虽然我们可以按照以下方式做点什么:
#include <iostream>
using namespace std;
struct FooA {
void operator()() {}
};
struct FooB {
bool operator()() { return false; }
};
struct FooC {
int operator()() { return 17; }
};
struct FooD {
double operator()() { return 3.14159; }
};
FooA fooA;
FooB fooB;
FooC fooC;
FooD fooD;
void barA() {}
bool barB() { return false; }
int barC() { return 17; }
double barD() { return 3.14159; }
namespace N
{
/* Functions */
template <typename R>
R run( R (*f)() ) { return (*f)(); }
bool run( void (*f)() ) { (*f)(); return true; }
/* Methods */
template <typename T, typename R>
R run( T & t, R (T::*f)() ) { return (t .* f) (); }
template <typename T>
bool run( T & t, void (T::*f)() ) { (t .* f) (); return true; }
};
#define SHOW(X) cout << # X " = " << (X) << endl;
#define BOUT(X) cout << # X " = " << boolToString(X) << endl;
const char * boolToString( int theBool )
{
switch ( theBool )
{
case true: return "true";
case false: return "false";
default: return "unknownvalue";
}
}
int main()
{
SHOW( N::run( barA ) );
BOUT( N::run( barA ) );
SHOW( N::run( barB ) );
BOUT( N::run( barB ) );
SHOW( N::run( barC ) );
SHOW( N::run( barD ) );
cout << endl;
SHOW( N::run(fooA,&FooA::operator()));
BOUT( N::run(fooA,&FooA::operator()));
SHOW( N::run(fooB,&FooB::operator()));
BOUT( N::run(fooB,&FooB::operator()));
SHOW( N::run(fooC,&FooC::operator()));
SHOW( N::run(fooD,&FooD::operator()));
}
您仍然需要将 &amp; CLASS :: operator() 作为参数提供。
最终,虽然我们可以确定对象的 operator()方法是否返回void,但我们通常不能基于返回类型重载。
我们可以通过模板专业化解决这个超载限制。但后来我们陷入了这种丑陋,我们仍然需要指定类型...特别是返回类型!手动,或通过传入一个合适的参数,我们可以从中提取必要的类型。
顺便说一句:#define宏也无济于事。像?:工具需要相同的类型?并且:部分。所以这是我能做的最好的......
当然......
如果您不需要返回类型...
如果您只是将结果传递给另一个函数......
您可以这样做:
#include <iostream>
using namespace std;
struct FooA {
void operator()() {}
};
struct FooB {
bool operator()() { return false; }
};
struct FooC {
int operator()() { return 17; }
};
struct FooD {
double operator()() { return 3.14159; }
};
FooA fooA;
FooB fooB;
FooC fooC;
FooD fooD;
void barA() {}
bool barB() { return false; }
int barC() { return 17; }
double barD() { return 3.14159; }
#define SHOW(X) cout << # X " = " << (X) << endl;
namespace N
{
template <typename T, typename R>
R run( T & t, R (T::*f)() ) { return (t .* f) (); }
template <typename T>
bool run( T & t, void (T::*f)() ) { (t .* f) (); return true; }
template <typename T>
void R( T & t )
{
SHOW( N::run( t, &T::operator() ) );
}
template <typename T>
void R( T (*f)() )
{
SHOW( (*f)() );
}
void R( void (*f)() )
{
(*f)();
SHOW( true );
}
};
int main()
{
N::R( barA );
N::R( barB );
N::R( barC );
N::R( barD );
N::R( fooA );
N::R( fooB );
N::R( fooC );
N::R( fooD );
}
答案 3 :(得分:0)
使用C ++ 0x,您可以使用decltype
轻松完成。
答案 4 :(得分:0)
如果您可以使用Boost
,则可能会提供以下代码。
我假设所有的函数/仿函数都是你的问题中的无效。
但是,为了使用它,必须在result_type
中定义
所有的仿函数(函数类)。
#include <boost/utility/result_of.hpp>
#include <boost/utility/enable_if.hpp>
#include <boost/type_traits.hpp>
using namespace boost; // Sorry, for brevity
template< class F >
// typename result_of< F() >::type
typename disable_if<
is_void< typename result_of< F() >::type >
, typename result_of< F() >::type
>::type
f( F const& x )
{
return x();
}
template< class F >
typename enable_if<
is_void< typename result_of< F() >::type >, bool
>::type
f( F const& x )
{
x();
return true;
}
template< class T >
T f( T x() )
{
return x();
}
bool f( void x() )
{
x();
return true;
}
static void void_f() {}
static int int_f() { return 1; }
struct V {
typedef void result_type;
result_type operator()() const {}
};
struct A {
typedef int result_type;
result_type operator()() const { return 1; }
};
int main()
{
A a;
V v;
f( void_f );
f( int_f );
f( a );
f( v );
}
希望这有帮助
答案 5 :(得分:-1)
尝试专门针对void返回类型:
template<class F>
class traits;
template<class F, class T>
class traits<T (F)()>;
template<class F>
class traits<void (F)()>;
我认为......