2016-12-28 134 views
1

比方說,我們有一個包裝模板函數(或成員函數)是這樣的:顯式模板實例的可變參數模板

template <class... T> void f(T... args) { 
    _f(args...); 
} 
void _f(int a1, ...); // variadic old style function 

凡功能_f(在第三方庫,我們不能修改定義)接受幾種參數類型的組合,並且期望在包裝水平上限制可能的參數。
如果我們有數百個具有不同可能參數類型的函數,那麼使用命名參數手動定義重載函數會太龐大。用簡單的宏和可能類型的列表來定義這樣的函數會更好。允許迭代參數列表以構造命名參數的Boost宏太重了。
是否有一種優雅的方式來限制聲明級別的可能參數?

+1

哦......'_f'是一種舊式的非模板變量函數。 '...'不僅僅代表你爲了簡潔而省略的東西,它實際上就是C++的特殊功能。是的,那麼我的答案確實無效,所以我刪除了它。 – hvd

+0

無論如何,謝謝。看來我並不太精確。 –

+0

@ hvd我得到了你的答案,並重新使用了一些特徵。也許它現在有效。 – skypjack

回答

2

您可以使用特徵來定義的基於它們的類型參數列表接受。
它遵循最小,工作示例:

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); 
} 

最後invokation會給你一個編譯時錯誤<int, int, int>不是結構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。不過,我早就走了與Boost.PP,SOOO實現它...

#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)); \ 
    } 

擴展爲:

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

謝謝,這絕對是可能的解決方案。 –