简体   繁体   English

c ++函数模板专业化

[英]c++ function template specialization

I'm trying to write a function that accepts a variable number of arguments of variable types. 我正在尝试编写一个函数,该函数接受可变数量的变量类型的参数。 The types will always be POD except for one case where there will be a List of POD. 这些类型将始终为POD,除非有一个POD列表的情况。 I have acheived this with paramter pack expansion and recursive template function calls. 我已经通过参数包扩展和递归模板函数调用实现了这一点。

The function is currently working for all overrides of POD with template specialization, but I want to create a template specialization for the List but keep the list templated. 该函数当前可用于模板特化的POD的所有替代,但是我想为列表创建模板特化,但保持列表模板化。 I understand that this may be impossible as this is effectively partial specialization at the function level. 我知道这可能是不可能的,因为这实际上是功能级别的部分专业化。 I am wondering about workarounds for this kind of a scenario. 我想知道这种情况下的解决方法。

Here is what I'm doing. 这是我在做什么。

template<typename T, typename ...TArgs> 
void Params2(T value, TArgs... args) {
        Params2(value);
        Params2(args...);
}
template<typename T>
inline void Params2(T c) { //invalid msg }

template <> inline void Params2<unsigned char>(unsigned char c) { //do something with char }
template <> inline void Params2<char>(char c) { //do something with uchar }
template <> inline void Params2<unsigned short>(unsigned short c) { //do something with short }
template <> inline void Params2<short>(short c) { //do something with ushort }

// more POD overrides 

If I do the following, it works because I have fully defined the type of the list: 如果我执行以下操作,那么它将起作用,因为我已经完全定义了列表的类型:

template <>  
inline void Params2< libfc::List<int> >(libfc::List<int> l) 
{ 
    for (auto itt = l.Begin(); itt != l.End(); ++itt) 
    { 
        //do something with each int
    } 
}

what I want to be able to do is: 我想要做的是:

template <>
template <typename R>
inline void Params2<libfc::List<R> >(libfc::List<R>) { 
    //do something with for each element of type R
}

I'd prefer not to make an override for each type of List that the function can take, but I can accept that if there is no better option. 我不想对函数可以使用的每种List类型进行覆盖,但是如果没有更好的选择,我可以接受。

edit: The calling application would invoke this functionality along the lines of (not valid code, just example): 编辑:调用应用程序将按照以下方式调用此功能(无效代码,仅作为示例):

Params2(10, 25, "test", List<int> { 5, 10 }, List<double> { 3.14, 9.81 } );

Use overload instead of specialization 使用重载而不是专业化

inline void Params2(unsigned char c) { //do something with char }
inline void Params2(char c) { //do something with uchar }
inline void Params2(unsigned short c) { //do something with short }
inline void Params2(short c) { //do something with ushort }

template<typename T> 
void Params2(const std::list<T>& value) {
// list
}


template<typename T, typename ...TArgs> 
void Params2(T value, TArgs... args) {
        Params2(value);
        Params2(args...);
}

or use generic method and class specialization 或使用通用方法和类专门化

template<typename T> 
struct helper;

template<> 
struct helper<unsigned char> { void operator () (unsigned char c) { /**/}};
template<> 
struct helper<char> { void operator () (char c) { /**/}};
template<typename T> 
struct helper<std::list<T>> { void operator () (const std::list<T>& l) { /**/}};

template<typename T> 
void Params2(const T& t) {
    helper<T>{}(t);
}

Using std::enable_if() , you can make templates that will take a mix of primitive data and "lists" of primitive data. 使用std::enable_if() ,您可以制作将原始数据和原始数据“列表”混合使用的模板。 The trick here is that anything that has a const_iterator type and a begin() method that returns a type convertible to that type will be treated as a list, and everything else will be get routed to the appropriate overloads. 这里的诀窍是,任何具有const_iterator类型和begin()方法(可返回可转换为该类型的类型begin()方法都将被视为列表,而其他所有方法都将被路由到适当的重载。

void foo(const int& t) { std::cout << "int: " << t << std::endl; }
void foo(const double& t) { std::cout << "double: " << t << std::endl; }

template<typename T,
         typename std::enable_if<
             std::is_convertible<
                 decltype(std::declval<const T&>().begin()),
                 typename T::const_iterator
             >::value
         >::type* = nullptr>
void foo(const T& t) {
    auto begin = t.begin();
    for(;begin != t.end(); ++begin) {
        foo(*begin);
    }
}

template<typename T,
         typename... TArgs>
void foo(const T& first, TArgs... args) {
    foo(first);
    foo(args...);
}

int main() {
    std::list<int> asdf{3, 4, 5};
    std::vector<double> vec{7, 8, 9};
    foo(1, 2.0, asdf, 6, vec);
}

Output: 输出:

int: 1 整数:1
double: 2 双倍:2
int: 3 整数:3
int: 4 整数:4
int: 5 整数:5
int: 6 整数:6
double: 7 双倍:7
double: 8 双倍:8
double: 9 双倍:9

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

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