仅使用一个类定义来重载模板化的类模板参数

问题描述

基本上,我正在尝试创建一个模板化的类,该类可以采用用户友好的方式进行实例化,也可以采用提供更多可配置性的更复杂方式进行实例化。我想提供这两种实例化方法,而不必复制API。

该类看起来类似于:

// templates that offer a lot of configurability
template<typename T,typename some_probably_awful_to_type_nested_class>
class has_my_api {

};

// templates that are easy to use
template<typename T,int i>
class has_my_api {

};

这个想法是我可以用some_probably_awful_to_type_nested_class构建i的通用版本,但是两个类将调用完全相同的api。

我知道我可以通过使用实际的API使用内部类型并让这两个类中的每个类的API都对该内部类进行调用来实现此目的,但我正在寻找一种无需重复执行代码方法。 / p>

以下是我正在寻找的更具体的示例:

#define DEFAULT_CONfig 0


//////////////////////////////////////////////////////////////////////
// nested classes themselves
template<typename T>
class inner_nested_class {
    // some fairly complex api
};

template<typename T,typename inner_nested_class_t,int configuration_flags = DEFAULT_CONfig>
class outer_nested_class {
    // some data structure of inner_nested_class
};

//////////////////////////////////////////////////////////////////////
// Helpers for creating nested_class from int seed
template<typename T,int i>
struct nested_class_creator;

template<typename T>
struct nested_class_creator<T,0> {
    typedef inner_nested_class<T> type;
};

template<typename T,int i>
struct nested_class_creator {
    typedef outer_nested_class<T,typename nested_class_creator<T,i - 1>::type> type;
};


template<typename T,typename outer_nested_class_t>
class manager_class {
    manager_class() = default;
    
    int foo();

    int bar();

    int baz();
    
    // some fairly involved additional API...
};


/* What i do NOT want to do 

template<typename T,typename outer_nested_class_t>
class manager_class_api {
    manager_class<T,outer_nested_class_t> inner_m;

    int foo() { return inner_m.foo() };

    int bar() { return inner_m.bar() };

    int baz() { return inner_m.baz() };
};

template<typename T,int i>
class manager_class_api {
    manager_class<T,i>::type> inner_m;

    int foo() { return inner_m.foo() };

    int bar() { return inner_m.bar() };

    int baz() { return inner_m.baz() };
};
*/

/* 
have tried... where the unified api Could be called through _manager_class

template<typename T,int i>
using _manager_class = manager_class <T,i>::type>;

template<typename T,typename outer_nested_class_t>
using _manager_class = manager_class <T,outer_nested_class_t>;

But obvIoUsly it does not work...
*/

int
main() {
    manager_class <int,outer_nested_class<int,inner_nested_class<int>,0x4>,0x3>> manager_with_user_specified_configs;

    // how do I do this?
    //manager_class <int,3> manager_with_simply_api;
}

这可能吗?如果可以,我该怎么办?

我很高兴使用任何版本的C ++> = 11

注意:我知道我可以为此使用预处理器宏作为更坏的情况。如果可能的话,我宁愿找到一个解决方案,以便用户可以简单地指定一个int或类型。

解决方法

我认为我们不能拥有可以接受类型或相同类型值的模板。

作为解决方法,您可以将值包装在类型(std::integral_constant)中(并可能提供UDL以允许3_c而不是std::integral_constant<int,3>)。

template <char... cs>
auto operator ""_c ()
{
    constexpr int n = [](){
        auto res = 0;
        
        for (auto c : {cs...}) {
            res *= 10;
            res += c - '0';
        }
        return res;
    }();
    return std::integral_constant<int,n>{};
}

因此您将:

template<typename T,typename outer_nested_class_t>
class manager_class {
    manager_class() = default;
    
    int foo();
    int bar();
    int baz();
    
    // some fairly involved additional API...
};


template<typename T,int i>
class manager_class<T,std::integral_constant<i>> :
    manager_class<T,typename nested_class_creator<T,i>::type>
{
};

您可以避免使用别名包装器进行继承:

template<typename T,typename outer_nested_class_t>
class manager_class_api {
    using type = manager_class<T,outer_nested_class_t>;
};

template<typename T,int i>
class manager_class_api<T,std::integral_constant<i>>
{
    using type = manager_class<T,i>::type>;
};

template<typename T,typename outer_nested_class_t>
using manager_class_api_t = typename manager_class_api<T,outer_nested_class_t>::type;

用法:

manager_class_api_t<int,outer_nested_class<int,inner_nested_class<int>,0x4>,0x3>> manager_with_user_specified_configs;

manager_class_api_t<int,decltype(3_c)> manager_with_simply_api;