本文介绍了C ++ 11“后期绑定”模板参数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

请不要误解我的后期绑定,我的意思不是在运行时进行通常的后期绑定,我的意思是其他事情,找不到更好的词:

Please don't get my "late binding" wrong, I don't mean usual late binding at runtime, I mean something else and cannot find a better word for it:

考虑到我正在为某个值类型为 V 的容器(或类似)数据结构 Containor 工作需要使用比较器比较这些值,所以我的第一个模板如下所示:

Consider I am working on a container (or similar) data structure Containor for some value type V that needs to compare these values with a comparator, so my first template looks like this

template<typename Val, typename Comp = std::less<Val>>
struct Containor{};

现在,我的 Containor 结构利用了内部另一个容器。使用哪个容器也应该可以通过模板参数进行配置,可以说默认值为 std :: set 。因此,我的下一个 Container 版本如下:

Now, my Containor structure makes use of another container internally. Which container is to be used should be configurable by template arguments as well, lets say the default is std::set. So my next version of Containor looks like this:

template<typename Val, typename Comp = std::less<Val>, typename Cont = std::set<Val,Comp>>
struct Containor{};

,这里是代码开始闻到恕我直言的地方。只要用户对内部容器的默认实现感到满意,一切都很好。但是,假设他想使用新的Google btree集实现 btree :: btree_set 而不是 std :: set 。然后,他必须像这样实例化模板:

and here is where the code begins smelling IMHO. As long as the user is satisfied with the default implementation of the inner container, everything is fine. However, suppose he wants to use the new google btree set implementation btree::btree_set instead of std::set. Then he has to instanciate the template like this:

typedef Containor<int,std::less<int>,btree::btree_set<int,std::less<int>> MyContainor;
                                                     ^^^^^^^^^^^^^^^^^^^



Containor 类始终需要一组与其自己的前两个模板参数完全相同的类型和比较器。客户可以-偶然-在此处插入其他类型!另外,客户有选择正确参数的负担。在这种情况下,这可能很容易,但是如果内部容器必须是例如一组值类型对和其他类型的对,则很难。然后,客户端需要花费更多的时间才能正确设置内部集合的类型参数。

I have underlined the part where my problem lies. The CLIENT CODE has to instanciate the btree_set with the right parameters. This honestly sucks, because the Containor class always needs a set of exactly the same type and comparator as its own first two template arguments. The client can - by accident - insert other types here! In addition, the client has the burden of choosing the right parameters. This might be easy in this case, but it hard if the inner container must for example be a set of pairs of the value type and some other type. Then the client has an even harder time getting the type parameters of the inner set correct.

所以我想要的是一种方法,使客户端代码只处理原始数据模板和 Containor 在内部使用正确的参数实例化它,例如:

So what I want is a way in which the client code only hands in the raw template and the Containor internally instanciates it with the correct arguments, i.e. something like that:

template<typename Val, typename Comp = std::less<Val>, typename Cont = std::set >
struct Containor{
    typedef Cont<Val,Comp> innerSet; 
//  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ container instanciates the inner containor
};

typedef Containor<int,std::less<int>,btree::btree_set> MyContainor;
//                                   ^^^^^^^^^^^^^^^^
//                         client only hands in  raw template

当然,这不是有效的C ++!

Of course, this is no valid C++!

所以我考虑了解决此问题的方法。我能想到的唯一解决方案是为我要使用的所有数据结构编写绑定程序类,如下所示:

So I thought about ways to solve this problem. The only solution I could think of was writing "binder classes" for all data structures I want to use, like this:

struct btree_set_binder{

    template<typename V, typename C = std::less<V>>
    struct bind{
        typedef btree::btree_set<V,C> type;
    }
};

现在我可以用定义我的 Container 设置活页夹

Now I can define my Containor with a set binder

template<typename Val, typename Comp = std::less<Val>, typename ContBinder = btree_set_binder >
struct Containor{
    typedef btree_set_binder::bind<Val,Comp>::type innerSet; 
//          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ works like a charm
};

现在,用户必须仅提供所需的活页夹类和 Containor 将使用正确的参数实例化它。因此,这些绑定器类对我来说还可以,但是为所有容器编写绑定器类很麻烦。因此,在C ++ 11中是否有更好或更简便的方法来绑定模板参数 late,即在另一个模板中,该模板将原始模板作为参数进行检索。

Now, the user must only supply the desired binder class and the Containor will instanciate it with the right arguments. So these binder classes would be okay for me, but it is quite a hassle writing binder classes for all containers. So is there a better or easier way to bind template arguments "late" in C++11, i.e., inside another template that retrieves the raw template as parameter.

推荐答案

也许是您自己的比较器特征。

Maybe make your own comparator trait.

// Comparator trait primary template

template <typename T> stuct MyComparator
{
    typedef typename T::key_compare type;
};

// Comparator trait non-standard usage example

template <typename U, typename V, int N>
struct MyComparator<WeirdContainer<U, V, N>>
{
    typedef std::greater<V> type;
};

template <typename T, typename Cont = std::set<T>>
struct MyAdaptor
{
    typedef typename MyComparator<Cont>::type comparator_type;
    typedef T value_type;

    // ...
};

我将您的容器重命名为 MyAdaptor,因为这种构造通常称为

I've renamed your "Containor" to "MyAdaptor", since this sort of construction is usually called an "adaptor" class.

用法:

MyAdaptor<int> a;    // uses std::set<int> and std::less<int>

MyAdaptor<double, WeirdContainer<bool, double, 27>> b;






更新:在根据讨论,您甚至可以完全删除外部类型参数:


Update: In light of the discussion, you could even remove the outer type argument entirely:

template <typename Cont> struct MyBetterAdaptor
{
    typedef MyAdaptorTraits<Cont>::value_type value_type;
    typedef MyAdaptorTraits<Cont>::pred_type pred_type;

    // ...
};

要像这样使用:

MyBetterAdaptor<std::set<int>> c; // value type "int", predicate "std::less<int>"

MyAdaptorTraits 模板保留为锻炼。

这篇关于C ++ 11“后期绑定”模板参数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!