2016-12-28 20 views
1

は、このように我々はラッピングテンプレート関数(またはメンバ関数を)持っているとしましょう:明示的なテンプレートのインスタンス

(我々は変更することはできません、サードパーティのライブラリで定義された)機能 _fが受け入れる
template <class... T> void f(T... args) { 
    _f(args...); 
} 
void _f(int a1, ...); // variadic old style function 

可能なパラメータをラップレベルで制限することが望ましいであろう。
可能なパラメータの種類が異なるこのような関数が何百もある場合、名前付き引数を使用してオーバーロードされた関数を手動で定義するには大きすぎます。可能な型のリストを持つ単純なマクロを使用して、そのような関数を定義する方が良いでしょう。引数のリストを反復して名前付き引数を作成することを可能にするBoostのマクロはあまりにも重いです。
宣言レベルで可能な引数を制限するエレガントな方法はありますか?

+1

Oh ... '_f'は古いスタイルのテンプレートではない可変長関数です。 '...'は簡潔さのために省略したものを表すだけではなく、実際はC++の特別な機能です。ええ、私の答えは本当にうまくいかないので、私はそれを削除しました。とにかくありがとう。 – hvd

+0

あまりにも正確ではなかったようです。 –

+0

@hvd私はあなたの答えを得て、それを少し使いました。多分それは今働きます。 – skypjack

答えて

2

:しかし、私はすでにBoost.PPでそれを実装するためにオフに行っていた、すっごく...

#include <boost/preprocessor/seq/for_each_i.hpp> 
#include <boost/preprocessor/comma_if.hpp> 

#define DECL_PARAM(r, data, i, elem) \ 
    BOOST_PP_COMMA_IF(i) elem _ ## i 

#define FWD_PARAM(r, data, i, elem) \ 
    BOOST_PP_COMMA_IF(i) _ ## i 

#define DEF_FN_WRAPPER(name, delegate, params) \ 
    void name(BOOST_PP_SEQ_FOR_EACH_I(DECL_PARAM, ~, params)) { \ 
     delegate(BOOST_PP_SEQ_FOR_EACH_I(FWD_PARAM, ~, params)); \ 
    } 

はに展開されます。
最小限、実施例以下の:最後invokationは<int, int, int>のためにあなたのコンパイル時のエラーを与えるだろう

void _f(int, ...) {} 

template<typename...> struct accepts; 
template<> struct accepts<int, double, char> {}; 
template<> struct accepts<int, char, int> {}; 

template <class... T> 
auto f(T... args) -> decltype(accepts<T...>{}, void()) { 
    _f(args...); 
} 

int main() { 
    f(0, 0., 'c'); 
    f(0, 'c', 0); 
    // f(0, 0, 0); 
} 

は、構造体acceptsの有効専門ではありません。
これは、プライマリテンプレートが定義されておらず、必要に応じてより多くのスペシャライゼーションを導入して受け入れられたリストを制御できるためです。ここ


std::true_typestd::false_typestatic_assertに基づいてわずかに異なる解決策である。

#include<type_traits> 

void _f(int, ...) {} 

template<typename...> struct accepts: std::false_type {}; 
template<> struct accepts<int, double, char>: std::true_type {}; 
template<> struct accepts<int, char, int>: std::true_type {}; 

template <class... T> 
void f(T... args) { 
    static_assert(accepts<T...>::value, "!"); 
    _f(args...); 
} 

int main() { 
    f(0, 0., 'c'); 
    f(0, 'c', 0); 
    // f(0, 0, 0); 
} 

利点がある:

  • コンパイル時に、より意味のあるエラーメッセージ(ウェル、もし"!"を意味のあるものに置き換えます)
  • 可能性t o std::false_typeから継承して明示的にパラメータリストを無効にし、必要に応じて同時に文書化する。

不利な点は、もう少し冗長であることである。

1

まあ、hvdはスポットオンです。本当に欲しいのはSFINAEです。あなたは自分のタイプに基づいて、パラメータの容認されたリストを定義する特性を使用することができます

void f(int _0 , double _1 , std::string _2) { _f(_0 , _1 , _2); } 
+0

ありがとう、確かに可能な解決策です。 –

関連する問題