使用专用和非专用类型的模板重载

时间:2014-10-02 15:42:22

标签: c++ templates

template < typename...dummy >
class wrapper;

template < typename TYPE >
class wrapper < TYPE > {};

template < template < typename... > class TYPE, typename... PARAMS >
class wrapper < TYPE < PARAMS... > > {};

template < typename >
class templated_class {};
class normal_class {};

typedef wrapper < normal_class > normal_wrapper;
typedef wrapper < templated_class, int > templated_wrapper;

在错误

中明显编译上述结果

'templated_class': class template ( not specialized ) cannot be a template argument for 'dummy', an actual type was expected

如何让它发挥作用,以便wrapper可以接受normal_classtemplated_class作为第一个参数?我觉得有一个简单的方法,但我没有看到它,因为我太挂了问题。

我不能写的原因

typedef wrapper < templated_class < int > > templated_wrapper;

是因为typedef是由一个可变参数宏创建的,为了MCVE目的而剥离 - 看起来像这样:

#define first_va(f,...) f
#define createwrapper(...) \
    typedef wrapper < __VA_ARGS__ > first_va(__VA_ARGS__)_wrapper;

createwrapper(normal_class)
createwrapper(templated_class,int)

我不知道如何执行预处理器向导以在<>中的第一个之后包含所有参数,如果可能的话。

使用模板或宏的解决方案对我来说都是可以接受的,尽管我更喜欢模板解决方案。

2 个答案:

答案 0 :(得分:2)

#define createwrapper_single(f) \
    typedef wrapper<f> f##_wrapper;
#define createwrapper_multiple(f, ...) \
    typedef wrapper<f<__VA_ARGS__> > f##_wrapper;

#define pick_createwrapper(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, NAME, ...) NAME
#define createwrapper(...) \
    pick_createwrapper(__VA_ARGS__, createwrapper_multiple, createwrapper_multiple, \
    createwrapper_multiple, createwrapper_multiple, createwrapper_multiple, \
    createwrapper_multiple, createwrapper_multiple, createwrapper_multiple, \
    createwrapper_multiple, createwrapper_single, something_is_wrong_if_this_is_used)(__VA_ARGS__)

Demo。显然,如果你写的模板有超过9个参数,那么这会破坏,但你可以根据需要将它扩展到任意数量。


或者,您可以使用decltype和重载功能:

template <template < typename... > class T, typename... params>
wrapper<T<params...>> wrapper_helper();

template <typename T>
wrapper<T> wrapper_helper();

#define first_va(f,...) f
#define PASTE2(x, y) x##y
#define PASTE(x, y) PASTE2(x,y)
#define createwrapper(...) \
    typedef decltype(wrapper_helper< __VA_ARGS__ >()) \
            PASTE(first_va(__VA_ARGS__,_blank), _wrapper);

Demo

答案 1 :(得分:0)

你不能拥有它。一旦定义了具有简单typename类型的所有参数的模板(不是模板而不是值),所有特化都必须使用类型作为实际模板参数。相反,如果参数是模板,则相应的参数将始终是任何特化中的模板。也就是说,没有为类模板重载。

您正在尝试做不可能的事情,因为您混淆了部分特化中存在的两个括号分隔列表。我想我只是用代码live demo here来解释它。

#include <iostream>

template <typename...>            // <--- to instantiate, say `wrapper<whatever list of types>`
struct wrapper
{
  static void foo() {
    std::cout << "generic" << std::endl;
  }
};

template<typename T>
struct wrapper<T>                 // <--- to instantiate, say `wrapper<sometype>`
{
  static void foo() {
    std::cout << "one argument" << std::endl;
  }
};

// just an illustration
template <typename T>              // <--------------------------------------------------+
struct wrapper <int, double, T>    // <--- to instantiate, use this list of arguments    |
{                                  //          not this one -----------------------------+
                                   //          that is, say `wrapper<int, double, sometype>`
                                   //          not `wrapper<sometype>`
  static void foo() {
    std::cout << "three arguments (int, double, something)" << std::endl;
  }
};

template <template<typename ...> class T,   // <-----------------------------------------+
         typename K>               //                                                    |
struct wrapper<T<K>>               // <--- to instantiate, use this list of arguments    |
{                                  //         not this one ------------------------------+
                                   //         that is, say `wrapper<sometemplate<sometype>>`
  static void foo() {
        std::cout << "the template thingy" << std::endl;
  }
};

template <typename> class X {};

int main ()
{
  wrapper<int, int>::foo();
  wrapper<int>::foo();
  wrapper<int, double, X<int>>::foo();
  wrapper<X<int>>::foo();
}