2012-02-25 1 views
2

テンプレート付きC++関数を暗黙的にすべてのポインタをvoid*に変換する方法はありますか?私は軽量のLuaバインディングに取り組んでおり、void*のバージョンが必要なときは、すべてのポインタ型に対して全く同じ関数を書くのを避けたいと思います。テンプレートをすべてのポインタ型に一致させる方法はありますか?

宣言:

template<class T> 
T GetFromStack(lua_State* L, int index); 

定義:私はmyVariable = GetFromStack<MyStruct*>(L, 0);を呼び出すことだった場合

template<> void* GetFromStack<void*>(lua_State* L, int index) 
{ 
    return lua_touserdata(L, index); 
} 

、C++コンパイラは、私がMyStruct*する機能を定義していないと文句を言うでしょう。 バージョンと暗黙的に一致するポインタタイプをにすることは可能ですか?

EDIT:

私は本当にわからないんだけど、私の質問は少し混乱している方法を見てどのように単語へ。私は自動バインディングシステムを考え出しています。このGetFromStack関数は、別のテンプレート関数から呼び出されます。

このように実装されて
template<class T_return, class T_param1, class T_param2 > 
int LuaFunction(lua_State* L, T_return (*func)(T_param1,T_param2)); 

template<class T_return, class T_param1, class T_param2 > 
int LuaFunction(lua_State* L, T_return (*func)(T_param1,T_param2)) 
{ 
    T_param1 a = GetFromStack<T_param1>(L, 1); 
    T_param2 b = GetFromStack<T_param2>(L, 2); 
    T_return ret = func(a,b); 
    PushLuaType(L, ret); // <-- This is another templated function 
         // like GetFromStack that has the same problem 
    return 1; 
} 

私は、私は簡単なマクロでのLuaに公開したいものは何でも機能のLuaのバージョンを作成します。

#define DeclareLuaFunction(function) \ 
    static int ##function##_lua_(lua_State* L) \ 
    { \ 
     return LuaFunction(L, function); \ 
    } 

これはあまりにも長い間、私は事前に定義された型を使用すると、本当によく働きます。私はGetFromStackのすべての "基本的な"タイプ(int、floatなど)用に書かれています。明らかにvoid*です。しかし私は私のカスタムタイプのポインタのすべてのための1つを書く必要はありません。 MyStruct2を使用する関数を作成すると、別のバージョンのGetFromStackを書く必要があります。これは他のすべてのpointerバージョンと同じです。

このシステムは、このように使用されます。その後、あまりにも整数としてMyStruct*T_param2としてintとしてT_returnT_param1を持っているでしょう

struct MyStruct 
{ 
    int a; 
    float b; 
}; 

int AddToMyStruct(MyStruct* s, int x) 
{ 
    int original = s->a; 
    s->a += x; 
    return original; 
} 

DeclareLuaFunction(AddToMyStruct); 

。私はすでにintバージョンのGetFromStackPushLuaTypeを持っていますが、MyStruct*バージョンはありません。今実装されている方法では、すべての実装が同じであっても、新しいタイプのGetFromStackを作成する必要があります。

EDIT:型がポインタであるかどうかをコンパイルタイプで判断できる方法であれば、Andreasのソリューションがうまくいきます。私のT_param1がMyStruct*であれば、それはMyStructではなく、GetFromStackにそのまま渡されます。

+0

だからあなたは 'GetFromStackたい:として使用することができ

template <class T> T GetFromStack(lua_State *l, int index) { return GetFromStackHelper<is_pointer<T>::value, T>::GetFromStackFun(l, index); } 

:今どんな専門を持つべきではありませんGetFromStack機能、(L、0) 'は' MyStruct * 'ではなく 'void *'を返しますか?私はそれが役に立つかもしれない方法を見ていない。 'GetFromStack (L、0)'のようなものを読んだとき、私は実際に何かを行うことができるように、 'void *'ではなく 'MyStruct *'を返すことを期待しています。タイプが何であるか分からないときは 'void *'を使用しますが、この場合は事前に何かを知っています。 –

+3

私はあなたが何を求めているのか分かりません。ちょうど 'void * GetFromStack(lua_State * L、int index)'の何が間違っていますか? (つまり、テンプレートを使用していない) – CAFxX

+1

あなたはちょっと混乱しているようです。 lua_touserdata()の仕様はまさにあなたが求めているものです! 'void * lua_touserdata(lua_State * L、int index);'。 'void *'だけが必要なものであれば、そのまま使用してください。 –

答えて

2

ここで、あなたの追加情報に基づいて新しい試みがあります。前にも述べたように、C++ 11を使用することを選択した方がずっと簡単ですが、ほとんどの古いコンパイラでも同様に動作します。

まず、あなたのテンプレートのparam Tがポインタであるかどうかを検出する方法が必要になり、あなたは(好適である)std::is_pointer<>を使用したり、自分が好きなものを定義することができ、次のいずれか

template <class T> 
struct is_pointer 
{ 
    enum {value = false}; 
}; 

template <class T> 
struct is_pointer<T *> 
{ 
    enum {value = true}; 
}; 

template <class T> 
struct is_pointer<const T *> 
{ 
    enum {value = true}; 
}; 

次のあなたの実装を変更する必要がありますそれに基づいて。

template <bool ispointer, class T> 
struct GetFromStackHelper; 

template <> 
struct GetFromStackHelper<false, int> 
{ 
    static int GetFromStackFun(lua_State *l, int index) 
    { 
    return lua_tointeger(l, index); 
    } 
}; 

// ... add the rest of the built in types here 

template <class T> 
struct GetFromStackHelper<true, T> 
{ 
    static T GetFromStackFun(lua_State *l, int index) 
    { 
    return static_cast<T>(lua_touserdata(l, index)); 
    } 
}; 

最後に、我々は一緒とそれを結ぶ:(私はpublicを書くのが面倒だとして、あるいは構造体)我々はヘルパークラスを導入することを行うには、いくつかの専門分野、各通常タイプ用とポインタのための1つは持っています

int i = GetFromStack<int>(luaState, 6); 
MyStruct *p = GetFromStack<MyStruct *>(luaState, 5); 
+0

これはまさに私が探しているものですが、 'GetFromStack'を呼び出すテンプレート関数ではうまくいかないと思います。私はいくつかのより多くの情報で私の元の質問を明確にしました。 – Kyle

+0

申し訳ありません、私はあなたのアップデートを逃しました。これは完全に機能します。ありがとう! – Kyle

0

私は、関数ポインタを渡すことについて

どのようにこれはあなたが探しているものであればかなりわからないんだけど、...?

あなたのコンパイラは恐らく警告を与えますが、それはうまくいくはずです。

void *GetFromStack(void *p, int index, void * (*func)(void *, int)) { 
    return func(p, index); 
} 

void * (*func)(void *, int)ボイドポインタとINTを取り、あなたがGetFromStackに第2パラメータとして供給ボイドポインタを返すものに関数ポインタです。参照演算子&を使用して、呼び出す関数の関数ポインタを取得します。

3

私が正しく理解していれば、関数はさまざまな型に対して別々に実装する必要がありますが、実装はすべてのポインタ型で同じになります。

値がパラメータとして渡された場合は、通常の関数オーバーロードを使用します。この場合、enable_ifを使用できます。

template<typename T> 
typename std::enable_if<std::is_pointer<T>::value, T>::type 
    GetFromStack(lua_State* L, int index) 
{ 
    return lua_touserdata(L, index); 
} 
+0

'std :: enable_if'はC++ 03の一部ではありません。どちらも 'std :: is_pointer'ではありません。 –

+0

@ avakar:可能ならば、標準に準拠した実装を好むだろう。 C++ 98が理想的です。私はより多くの情報でオリジナルの質問を更新しました。 – Kyle

+0

@Kyle: 'enable_if <>'は、ブーストライブラリで利用できます。[例](https://gist.github.com/bd7c7d7da73aac8183ea) – jfs

関連する問題