1
私はこのコードをSFINAEとデフォルトのテンプレート引数に依存しています。予想されるように、それは最後の二つのコメント行を除いて、動作します:関数テンプレートのオーバーロードのアドレスを取得します
#include <tuple>
#include <iostream>
using namespace std;
template<typename T> void push(T val){
cout<<val<<endl;
}
template<typename T> T to(){
T dummy;
cin>>dummy;
return dummy;
}
template<typename T, T> class function_proxy{
static_assert(sizeof(T)!=sizeof(T), "Error: function_proxy works with functions (duh)");
};
template<typename Return, typename... Args, Return(*func)(Args...)> class function_proxy<Return(*)(Args...), func>{
static Return call(Args... args){
return func(args...);
}
template<typename... retrieved> static Return call(retrieved... read){
return call(read..., to<typename tuple_element<sizeof...(read), tuple<Args...> >::type >());
}
public:
template<typename Ret=Return, typename enable_if<!is_void<Ret>::value, int>::type=0>
static int wrapper(){
push(call());
return 1;
}
template<typename Ret=Return, typename enable_if<is_void<Ret>::value, int>::type=0>
static int wrapper(){
call();
return 0;
}
};
int f(int arg){ return arg*3; }
void g(){ cout<<"g does nothing"<<endl; }
int main(){
//SFINAE works nicely
function_proxy<decltype(&f), &f>::wrapper();
function_proxy<decltype(&g), &g>::wrapper();
//Here it doesn't, even though there should be no ambiguity:
//function_proxy<decltype(&f), &f>::wrapper;
//function_proxy<decltype(&g), &g>::wrapper;
}
あなたは、私はテンプレート関数を呼び出すとき、SFINAEはその仕事をしていることがわかります。しかし、不正な形式ではない唯一の機能のアドレスを取ろうとすると、g ++は、オーバーロードされた関数のアドレスを解決できないという不満を持ちます。
これらのオーバーロードされた関数の最初のテンプレートパラメータを明示的に伝えなくても、この問題を解決する方法はありますか?理論的には、それは冗長です。また、このヘルパークラスを使用する私のコードは非常に汎用的なので、ここでの戻り値の型はf
とg
であるため、フェッチするのは簡単ではないかもしれません。
を参照してください。ポイントは、間違いなく安全だと思います。あなたがこのようにアドレスを指定するときは、SFINAEを使うのが理にかなっています。これが将来の標準で起こるのを見る機会はありますか? –
@LorenzoPistone - 誰が知っていますか? SFINAEのこのようなイントロスペクションのような使用は、診断、使いやすさ(テンプレートと関数呼び出し)、コンパイラの実装の容易性(型減算、過負荷解決)のバランスに焦点を当てた元の提案の一部ではありませんでした。他の言語の中には標準的なイントロスペクション機能があり、C++はいつかその訴訟に従うかもしれません。あるいは、将来はSFINAEをもっともたらすかもしれません。 –