具有专用和非专用类型的模板重载

Template overloading with specialized and unspecialized type

本文关键字:专用 重载 类型      更新时间:2023-10-16
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)

而且我不知道如何执行预处理器魔法以在 <> 中的第一个参数之后括起所有参数,如果可能的话。

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

#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__)

演示。显然,正如所写的那样,如果您疯狂地编写一个包含 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);

演示。

你不能这样。定义具有简单typename类型(不是模板也不是值(的所有参数的模板后,所有专用化都必须使用类型作为实际模板参数。相反,如果参数是模板,则相应的参数将始终是任何专用化的模板。也就是说,类模板没有重载。

您正在尝试做不可能的事情,因为您将部分专业化中存在的两个括号分隔列表混淆了。我想我会在这里用代码现场演示来解释它。

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