繁体   English   中英

可变参数模板的显式模板实例化

[英]Explicit template instantiation for variadic templates

假设我们有一个包装模板函数(或成员函数),如下所示:

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

如果函数_f (在我们无法修改的第三方库中定义)接受参数类型的几种组合,则希望在包装级别限制可能的参数。
如果我们有成百上千个具有不同可能参数类型的函数,那么使用命名参数手动定义重载函数将太庞大。 最好使用带有可能类型列表的简单宏来定义此类函数。 允许迭代参数列表以构造命名参数的Boost宏看起来太繁重。
有没有一种优雅的方法可以在声明级别限制可能的参数?

您可以使用特征来根据参数的类型定义可接受的参数列表。
它遵循一个最小的有效示例:

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

最后一次调用会给您一个编译时错误,因为<int, int, int>不是struct 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);
}

优点是:

  • 在编译时显示更有意义的错误消息(好吧,如果您将"!"替换为有意义的内容)
  • 通过从std::false_type继承并显式禁用参数列表的可能性,并在需要时同时进行记录

缺点是它比较冗长。

好吧, hvd亮点。 您真正想要的是SFINAE。 但是我已经开始使用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)); \
    }

扩展为:

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM