Template with a specialized template class parameter. How?

I think my problem is best explained with how I want the code to look. Only problem is it doesn't work (Line 11). I have some experience with templates but I'm not a pro.

Basically I want the "Channels<3>" to be a type that I can use to specify a Cable with similar to vector<float/int> it would be Cable<Channels<2 or 3>>.

What have I messed up with the syntax?

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
42
43
44
45
46
47
48
49

#include <iostream>
#include <vector>
using namespace std;

template<int channel_count>
struct Channels {
	static const int channels = channel_count;
};

template< Channels<int> T >
class Cable
{
	public:
	const int channels = T::channels
	vector<float> audio[T::channels];
	
	Cable(){
		for(int i = 0; i < T::channels; i++){
			for(int s = 0; s < 5; s++){
				audio[i].push_back(i);
			}
		}
	}
	
};


int main() {
	
	Cable<Channels<3>> c;
	
	cout << "num: " << c.channels << endl;
	for(int i = 0; i < c.channels; i++){
		cout << i << ": ";
		for(int s = 0; s < c.audio[i].size(); s++){
			cout << " " << c.audio[i][s];
		}
		cout << endl;
	}

// I want this output:
// 0: 0 0 0 0 0
// 1: 1 1 1 1 1
// 2: 2 2 2 2 2

	return 0;
}
Last edited on
Thanks JL.

I don't really like the 2nd and 3rd because they don't have the syntax I would like. I really want the syntax " Cable<Static_Property<value>> " for some really nice flexibility when things get more complicated.

With the first solution, it breaks with any type that has a "channels" property...

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
template<int channel_count>
struct Channels {
	static const int channels = channel_count;
};

//adding this...
template<int channel_count>
struct Tricked {
    static constexpr int channels = channel_count;
};

int main() {
        // compiles...
        // but that makes no sense
	Cable< Tricked<3> > c;
        return 0;
}


I want to add specialization later on based on Cable<Channels<2>>, Cable<Channels<3>>, etc that do specific mixing, or connections/io and at a minimum the number of channels have to match. It would be nice to catch that at compile time.

So something like this would work...
1
2
3
4
5
6
7

Mixer< Slots<20>, Cable<Channels<3>> > m;
Cable<Channels<2>> c2;
Cable<Channels<3>> c3;
m.add_to_mix(c3);  // ok
m.add_to_mix(c2);  // should fail


Is that possible?
Last edited on
> I really want the syntax " Cable<Static_Property<value>> "
> it breaks with any type that has a "channels" property...
> It would be nice to catch that at compile time.

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
#include <iostream>
#include <type_traits>
#include <vector>

template< int CHANNEL_COUNT > struct Channels {

    static constexpr int channels = CHANNEL_COUNT ;
};

template< typename T, int = 0 > struct is_channel_ : std::false_type {} ;
template< int N > struct is_channel_< Channels<N> > : std::true_type {} ;
template< typename T > constexpr bool is_channel() { return is_channel_<T>::value ; }

template< typename T > struct Cable {

    static_assert( is_channel<T>(), "Cable must be intantiated with type Channels<N>" ) ;

    static constexpr int channels = T::channels;
	std::vector<float> audio[channels];

	Cable() {
		for( int i = 0; i < channels; ++i ) {
			for( int s = 0; s < 5; s++ ) audio[i].push_back(i);
        }
	}
};

template<int channel_count>
struct Tricked {
    static constexpr int channels = channel_count;
};

int main() {
    Cable< Channels<3> > this_is_fine ;
    std::cout << "ok\n\n" ;
    
    #ifdef NOT_OK
        Cable< Tricked<3> > this_is_not_ok ;
    #endif // NOT_OK
}

echo 'test Cable< Channels<3> >' && clang++ -std=c++14 -stdlib=libc++ -O2 -Wall -Wextra -pedantic-errors -pthread main.cpp -lsupc++ && ./a.out

echo 'test Cable< Tricked<3> >' && clang++ -DNOT_OK -std=c++14 -stdlib=libc++ -O2 -Wall -Wextra -pedantic-errors -pthread main.cpp -lsupc++ && ./a.out

test Cable< Channels<3> >
ok

test Cable< Tricked<3> >
main.cpp:16:5: error: static_assert failed "Cable must be intantiated with type Channels<N>"
    static_assert( is_channel<T>(), "Cable must be intantiated with type Channels<N>" ) ;
    ^              ~~~~~~~~~~~~~~~
main.cpp:38:29: note: in instantiation of template class 'Cable<Tricked<3> >' requested here
        Cable< Tricked<3> > this_is_not_ok ;
                            ^
1 error generated.

http://coliru.stacked-crooked.com/a/5fb2c5169c3947f2
Thanks again JLBorges. You introduced me to some new template ideas and solved my problem cleanly. Wizardly.
Registered users can post here. Sign in or register to post.