C++ 可变模板的显式模板实例化
假设我们有这样一个包装模板函数(或成员函数):C++ 可变模板的显式模板实例化,c++,templates,overloading,instantiation,explicit,C++,Templates,Overloading,Instantiation,Explicit,假设我们有这样一个包装模板函数(或成员函数): template <class... T> void f(T... args) { _f(args...); } void _f(int a1, ...); // variadic old style function 模板无效f(T…args){ _f(args…); } void _f(int a1,…);//变分旧式函数 函数\u f(在我们无法修改的第三方库中定义)接受多种参数类型的组合,最好在包装级别限制可能的参数
template <class... T> void f(T... args) {
_f(args...);
}
void _f(int a1, ...); // variadic old style function
模板无效f(T…args){
_f(args…);
}
void _f(int a1,…);//变分旧式函数
函数\u f
(在我们无法修改的第三方库中定义)接受多种参数类型的组合,最好在包装级别限制可能的参数。如果我们有数百个具有不同可能参数类型的函数,那么手动定义带有命名参数的重载函数就太庞大了。最好使用带有可能类型列表的简单宏来定义此类函数。Boost允许迭代参数列表以构造命名参数的宏看起来太重了。
有没有一种优雅的方法可以在声明级别限制可能的参数?很好,这是正确的。你真正想要的是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, ...) {}
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);
}
优点是:
- 编译时一条更有意义的错误消息(如果您用有意义的内容替换
)“!”
- 可以通过继承
显式禁用参数列表,并在需要时记录它std::false\u type
缺点是它有点冗长。谢谢,这绝对是可能的解决方案。哦
\u f
是一种旧式的非模板变量函数。<代码>…>代码>不仅仅代表了你为简洁而忽略的东西,实际上是C++的特定特性。是的,那我的答案真的不行了,所以我把它删掉了。谢谢。看来我不太准确。@hvd我得到了你的答案,并用特征对它进行了修改。也许现在可以了。
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);
}
#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);
}