Is it possible to create a vector of multiple type of specialized template classes?

I'm lost, quite frankly. I have an example piece of code where I I have a template class and one instance of a specialized version of that class. In the main program, I am simply trying to create a vector that can hold instances of the specializations of that template class. My question is, is it even possible to create a vector of the various specialized instances of a template class? I know I can do it by being specific about which template class specialization. I hope that made sense.

Is there a better approach if there is not a way to do this?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <vector>
#include <memory>

using namespace std;

enum class Recipes : int { UNKNOWN = -1, JaJangMyeon, COUNT };

template<Recipes R> class recipeClass
{
public:
    recipeClass ( ) { }
};

template<> class recipeClass<Recipes::JaJangMyeon>
{
public:
    recipeClass ( ) { cout << __func__ << " JaJangMyeon>" << endl; }
};

int main ( int argc, char** argv )
{
    /*
     * This section works, being specific about recipeClass I'm vectorizing
     */
    std::vector<recipeClass<Recipes::JaJangMyeon> *> rcVector1;
    rcVector1.emplace_back ( new recipeClass<Recipes::JaJangMyeon>( ) );
    /*
     * This is what I'd like to do... which of course won't compile
     */
    std::vector<recipeClass<Recipes::*> *> rcVector2;
    rcVector2.emplace_back ( new recipeClass<Recipes::JaJangMyeon>( ) );

    return 0;
}
Last edited on
I was able to find a solution to my problem (besides the genetic one) doing the following, by creating a base class and making it the basis for the vector... Does anyone have a cleaner solution that doesn't necessarily require creating a entire new class just to stuff the vector?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
class recipeBase
{
    
};

enum class Recipes : int { UNKNOWN = -1, JaJangMyeon, COUNT };

template<Recipes R> class recipeClass : private recipeBase
{
public:
    recipeClass ( ) { }
};

template<> class recipeClass<Recipes::JaJangMyeon>
{
public:
    recipeClass ( ) { cout << __func__ << " JaJangMyeon" << endl; }
};

template<> class recipeClass<Recipes::COUNT>
{
public:
    recipeClass ( ) { cout << __func__ << " COUNT" << endl; }
};

int main ( int argc, char** argv )
{
    /*
     * This section works, being specific about which recipeClass I'm vectorizing
     */
    std::vector<recipeClass<Recipes::JaJangMyeon> *> rcVector1;
    rcVector1.emplace_back ( new recipeClass<Recipes::JaJangMyeon>( ) );
    /*
     * This is what I'd like to do... which of course won't compile
     */
    std::vector<recipeBase *> rcVector2;
    rcVector2.emplace_back ( (recipeBase *) new recipeClass<Recipes::JaJangMyeon>( ) );
    rcVector2.emplace_back ( (recipeBase *) new recipeClass<Recipes::COUNT>( ) );

    return 0;
}
> a cleaner solution that doesn't necessarily require creating a entire new class just to stuff the vector?

We can let the library do the hard work behind the scenes.

If the set of candidate types is bounded at compile time, we can use std::variant
https://en.cppreference.com/w/cpp/utility/variant
otherwise, std::any https://en.cppreference.com/w/cpp/utility/any

For instance:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#include <iostream>
#include <variant>
#include <vector>

template < typename T > struct A
{
    friend std::ostream& operator << ( std::ostream& stm, const A<T>& )
    { return stm << "generic A<T>" ; }
};

template <> struct A<int>
{
    friend std::ostream& operator << ( std::ostream& stm, const A<int>& )
    { return stm << "specialisation A<int>" ; }
};

template <> struct A<void>
{
    friend std::ostream& operator << ( std::ostream& stm, const A<void>& )
    { return stm << "specialisation A<void>" ; }
};

int main()
{
    using variant = std::variant< A<char>, A<int>, A<long>, A<void>, int > ;

    const std::vector<variant> seq { variant( A<char>{} ), A<int>{}, A<long>{}, A<void>{}, A<int>{}, 23456 };

    for( const auto& v : seq ) std::visit( []( auto&& a ) { std::cout << a << '\n' ; }, v ) ;
}

http://coliru.stacked-crooked.com/a/0b719118ee474348
Oh my, those looks so promising!

I will have to keep those in mind; unfortunately, I'm using Netbeans 8.2 and it provides support no later than C++14. So it appears that both variant and any are unavailable.

Figures, I've always been the guy who builds the engines but forget to invent the gas.

Any other options? I tried my solution and all I did was end up disemboweling my original code and making a mess. Just a wee bit frustrated at this point
In C++14, we could use boost::variant
It is a header only library: https://www.boost.org/doc/libs/1_68_0/doc/html/variant.html

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#include <iostream>
#include <boost/variant.hpp>
#include <vector>

template < typename T > struct A
{
    friend std::ostream& operator << ( std::ostream& stm, const A<T>& )
    { return stm << "generic A<T>" ; }
};

template <> struct A<int>
{
    friend std::ostream& operator << ( std::ostream& stm, const A<int>& )
    { return stm << "specialisation A<int>" ; }
};

template <> struct A<void>
{
    friend std::ostream& operator << ( std::ostream& stm, const A<void>& )
    { return stm << "specialisation A<void>" ; }
};

int main()
{
    using variant = boost::variant< A<char>, A<int>, A<long>, A<void>, int > ;
    std::vector<variant> seq { variant( A<char>{} ), A<int>{}, A<long>{}, A<void>{}, A<int>{}, 23456 };

    for( const auto& v : seq ) boost::apply_visitor( []( auto&& a ) { std::cout << a << '\n' ; }, v ) ;
}

http://coliru.stacked-crooked.com/a/e12ae5088b6c54a0

There also is boost::any https://www.boost.org/doc/libs/1_68_0/doc/html/any.html
My goodness, that was worth waiting up for! I've seen a lot of code samples using boost. But have never used it myself. I will look at this this afternoon. It's almost 0900 here and I'm hitting the rack. After a nice plate of eggs over easy (bribed the chef) and half a hog's worth of bacon). Thanks so much!!!
Topic archived. No new replies allowed.