2

Often conceptually a template must be passed as a type argument and the compiler complains because this is not legal c++ - at least until and including c++11 (Update II: except see last example of non specialized template definition)

These concepts are often used and should have a name. See the code examples below if it is not clear what I mean.

My first thought was that this may also be called passing an incomplete type but this is not correct. Another user also states that he has no word for it and freely names it late binding of template arguments. I think his terminology visualizes the concept well.

My question is how do you call the idiom behind this or the involved templates properly?

UPDATE Kerrek suggests naming the idiom template rebinding. This name renders only a few google results. However I think it is a very good name too because the standard allocators call their related wrapped internal classes rebind.

In the following example you could configure if your database uses map or hashmap internally:

#include <map>
struct map_wrapper
{
    template<typename K, typename V>
    using type =  std::map<K,V>;
};
template<typename storage>
struct my_database
{
    typename storage::template type<int, int> x;
    typename storage::template type<int, double> y;
};
main ()
{
    my_database<map_wrapper> db;
    db.x[0] = 1;
    db.y[0] = 2.0;
}

Or similarly

#include <map>
#include <boost/mpl/apply.hpp>
template <typename storage>
struct my_database
{
    typename boost::mpl::apply<storage, int>::type x;
    typename boost::mpl::apply<storage, double>::type y;
};
int main ()
{
    my_database< std::map<int, boost::mpl::_1> > db;
    db.x[0] = 1;
    db.y[0] = 2.0;
}

Update II: To my embarrassment I did not know the following solution which is just passing a template as argument to a template instantiation. In this special case it is legal to pass a non-type.

#include <map>
#include <unordered_map>

template<template<typename...> class Storage>
struct my_database
{
    Storage <long,char> x;
    Storage <long,double> y;
};

int main ()
{
    my_database< std::map > db1;
    db1.x[0] = '1';
    db1.y[0] = 2.2;
    my_database< std::unordered_map > db2;
    db2.x[0] = '1';
    db2.y[0] = 2.2;
}

Examples of other ways to rebind or late bind template arguments are of course welcomed.

Community
  • 1
  • 1
Patrick Fromberg
  • 1,313
  • 11
  • 37
  • @Kerrek, I am not certain about the netiquette but do you welcome if I improve my question according to your suggestions and thus invalidate your comments? In any case I invite anyone to edit and improve my question. – Patrick Fromberg Nov 02 '13 at 04:48
  • That's perfectly fine. Comments are ephemeral, and you can flag them as "obsolete" if the original comment author doesn't delete them. If you make a comment like "@user: I've updated my post", then more often than not the commenter will come back and delete their obsolete comments... – Kerrek SB Nov 02 '13 at 14:46
  • I'd call your wrapper maneuver "template rebinding". I guess that's a moderately conventional term, but don't bank on it. – Kerrek SB Nov 02 '13 at 14:49
  • @KerrekSB, I have updated the question inspired by your comments and will remove one comment of mine. – Patrick Fromberg Nov 03 '13 at 03:45
  • Your map wrapper is somewhat roundabout, unless you really need the member-template `type` for your application. Otherwise, you could simply use a template template parameter for `my_database`: `template – Kerrek SB Nov 03 '13 at 10:24
  • Here is a [slightly more obscure example](http://stackoverflow.com/a/10488652/596781) of template argument rebinding... – Kerrek SB Nov 03 '13 at 10:26
  • @KerrekSB, I do not know how you mean roundabout and template template but I have added my understanding as last example (it makes use of dummy types to convert the template to a type so it can be passed as argument). It makes my point clear that it is not so easy to talk about many idioms. I am not sure if I am just not articulated enough or the nomenclature still needs maturing or both. – Patrick Fromberg Nov 04 '13 at 03:17
  • I've added some thoughts on your updated question to my answer. Not necessarily as an answer, but as thoughts. By the way, here's a rather [unrelated post](http://stackoverflow.com/questions/11723652/template-metaprogramming-trait-for-dissecting-a-specified-template-into-type) about template rebinding that you might find interesting. – Kerrek SB Nov 04 '13 at 08:52
  • I'm pretty sure boost::mpl uses rebind. Check `identity` metafunction. It has `BOOST_MPL_AUX_LAMBDA_SUPPORT` which is defined as a `rebind` struct with a `apply` template type inside. In my previous meta algorithms I called those kind of types "replicators". Which has helped me for example to make iterators and visitation possible. you generate the next iterator type thanks to its replicator, because the replicator "closes" (closure sense) information you don't have anymore on the client side. – v.oddou Apr 10 '15 at 02:18

1 Answers1

2

You've provided a template where a type is expected.

For what it's worth, GCC 4.8 gives a decent diagnostic:

template <typename> struct Foo;
template <typename> struct Bar;

int main()
{
    Foo<Bar> x;
}

Diagnostic:

In function ‘int main()’:
error: type/value mismatch at argument 1 in template parameter list for ‘template<class> struct Foo’
Foo<Bar> x;
          ^
error:   expected a type, got ‘Bar’

(GCC got a lot better since Clang started producing very nice error messages, so this may be recent; I imagine Clang would also give a useful error here.)


Concerning your updated question: The typical way to make a container adapter, or generally a class that needs a certain container which you want to be customizable, is to pass the entire container as a template parameter:

template <typename XContainer, typename YContainer>
struct Database
{
    XContainer xstorage;
    YContainer ystorage;
};

Database<std::map<int, double>, std::unordered_map<std::string, double>> db;
db.xstorage[1] = 2.5;
db.ystorage["foo"] = 4.5;

This is the most general solution since you can use any class that fits your needs, without requiring that class to have any particular structure.

As an alternative (which I do not recommend), if you want all your containers to be template specializations of the same template, you can pass the template in directly as a template parameer (a so-called template template parameter):

template <template <typename, typename, typename...> class CTmpl,
          typename XType,
          typename YType>
struct Database
{
    CTmpl<XType, double> x;
    CTmpl<YType, double> y;
};

Database<std::map, int, std::string> db;
// as above

This is a lot more restrictive: not only does your database now have to use the same data structure for everything, but the data structure also has to be given as a template with fixed first two parameters "key type" and "mapped type".

Kerrek SB
  • 464,522
  • 92
  • 875
  • 1,084
  • Actually I was happy with the name *template rebinding* which I did not know and as an answer I would have hooked it as correct. Your last solution however does absolutely not apply (one template argument for each map). Note that my *database* was a simplified example code. Imagine there are 1000 different maps used inside my database and I want to switch from binary trees to hashes. Your most helpful advise was to use clang which showed me that I can actually pass a template (not a type) as an argument in one case and thus I could fix my last example. – Patrick Fromberg Nov 07 '13 at 03:56
  • @PatrickFromberg This answer does not (currently) mention the word "rebind," as it shouldn't. That term applies to a template which allows transforming one specialization into another, such as `std::allocator` which provides a `rebind` member template. I think "wrapper class" suffices. – Potatoswatter Nov 12 '13 at 23:55
  • @Potatoswatter, I see your point regarding the rebinding which is only one way out of many to pass kind of template template argument [see here](http://stackoverflow.com/q/12362363/2712726). But a "wrapper class" is to general because there are many wrapping idioms for very different purposes totally unrelated to the question. After your comment *late template binding* would be my personal favorite as name for the idiom. – Patrick Fromberg Nov 13 '13 at 02:19
  • @PatrickFromberg But that terminology also applies if you don't have wrapper. Anyway, say whatever you like :) – Potatoswatter Nov 13 '13 at 05:18