私はclass A
データメンバーとして関数へのポインタが必要な場合:
class A
{
protected:
double (*ptrToFunction) ( double );
public:
...
//Setting function according to its name
void SetPtrToFunction( std::string fName );
};
しかし、ptrToFunction
を時々double
にし、時には--int
にしたい場合は、次のようにします。
//T is a typename
T(*ptrToFunction) ( double );
この場合、どのように宣言すればよいですか?
識別された共用体 はあなたのためにそれを行うことができます:
_class A
{
template<T>
using cb_type = T(double);
protected:
enum {IS_INT, IS_DOUBLE} cb_tag;
union {
cb_type<int> *ptrToIntFunction;
cb_type<double> *ptrToDoubleFunction;
};
public:
...
// Setting function according to its name
void SetPtrToFunction( std::string fName );
};
_
識別された共用体のより一般的で洗練されたソリューションは、C++ 17の_std::variant
_、または以前の標準リビジョンの_boost::variant
_で適用できます。
または、戻り値の型を完全に無視したい場合は、メンバーを std::function<void(double)>
に変換して、型消去の恩恵を受けることができます。 Callable
の概念では、ポインターを介した呼び出しがstatic_cast<void>(INVOKE(...))
に変換され、戻り値が何であれ、それが破棄されます。
宛先 イラスト :
_#include <functional>
#include <iostream>
int foo(double d) { std::cout << d << '\n'; return 0; }
char bar(double d) { std::cout << 2*d << '\n'; return '0'; }
int main() {
std::function<void(double)> cb;
cb = foo; cb(1.0);
cb = bar; cb(2.0);
return 0;
}
_
そして最後に、もしあなたが戻り値に気を配るが、保存したくない場合識別された共用体。次に、ユニオンと_std::function
_の動作について知っていると、上記の2つのアプローチを組み合わせることができます。
_#include <functional>
#include <iostream>
#include <cassert>
int foo(double d) { return d; }
double bar(double d) { return 2*d; }
struct Result {
union {
int i_res;
double d_res;
};
enum { IS_INT, IS_DOUBLE } u_tag;
Result(Result const&) = default;
Result(int i) : i_res{i}, u_tag{IS_INT} {}
Result(double d) : d_res{d}, u_tag{IS_DOUBLE} {}
Result& operator=(Result const&) = default;
auto& operator=(int i)
{ i_res = i; u_tag = IS_INT; return *this; }
auto& operator=(double d)
{ d_res = d; u_tag = IS_DOUBLE; return *this; }
};
int main() {
std::function<Result(double)> cb;
cb = foo;
auto r = cb(1.0);
assert(r.u_tag == Result::IS_INT);
std::cout << r.i_res << '\n';
cb = bar;
r = cb(2.0);
assert(r.u_tag == Result::IS_DOUBLE);
std::cout << r.d_res << '\n';
return 0;
}
_
例のように、クラスにテンプレートがない場合は、次のようにすることができます。
template <class T>
struct myStruct
{
static T (*ptrToFunction)(double);
};
関数のアドレスを取得するためにdlsym
/GetProcAddress
を使用しているようです。
この場合、CPUは実際にはこれらの呼び出しごとに異なる処理を実行するため、呼び出しを明確にするために少なくとも2つの呼び出しサイトが必要です。
enum ReturnType { rtInt, rtDouble };
void SetPtrToFunction( std::string fName , enum ReturnType typeOfReturn );
struct Function {
enum ReturnType rt;
union {
std::function< int(double) > mIntFunction;
std::function< double(double) > mDoubleFunction;
} u;
} mFunction;
したがって、関数は既知の戻り値の型でインスタンス化する必要があります。次に、これをタグ付き共用体で使用して、正しい関数呼び出しを取得します。
int A::doCall( double value ) {
if( mFunction.rt == rtInt ) {
int result = mFunction.mIntFunction( value );
} else if( mFunction.rt == rtDouble ) {
double result = mFunction.mDoubleFunction( value );
}
}