How can I pass value through a specialized template class?

Here is my problem
I have an existing no-template class A, currently being used by many places. I want to modify it with minimal impact on the exiting codes, in which I need to pass a template int parameter to make a compile time build (something like A<int>).

To do it, I was trying to change it as

template<typename T = bool, int VALUE = 0>
A{};

template<>
A<bool, int>
{
//current behavior
};

template<>
A<int, int SIZE>{
//new codes need value passed by SIZE
};

I was hoping I could simply call A<bool, 0>, my old codes will be called. In case I need the new feature, I can just call something like A<int, 10>. This does not work in template.

Is there a good technique in template programming to achieve this?
Thanks
Chris




I want to modify it with minimal impact on the exiting code

You should consider just introducing a new class template.

First of all, a class can't blindly be made into a class template without breaking source-level compatibility.

To see why, consider
1
2
3
// A was changed into a class template:
template <typename T = void> struct A {}; 
int main() { A a; } // fails to compile:  missing template argument list 

If A suddenly becomes a class template, the main function fails to compile because A<> is required.

Additionally, it's harder to write opaque templates, since they must (usually) be exposed directly to the client code. This means that changes to the implementation of a class template can affect binary compatibility. This is sometimes problematic, but it needs to be addressed separately.

You can conditionally allow users to use your new feature by doing something like this:
1
2
3
4
5
6
7
8
9
10
11
namespace mylib {
# if ! defined MYLIB_USE_V2
  inline
# endif
  namespace v1 { struct A { /* old implementation */ }; }

#if defined MYLIB_USE_V2
  inline
#endif
  namespace v2 { template <int I> struct A {  /* new implementation */ }; } 
}


To choose the new interface, a client can define MYLIB_USE_V2. The old implementation would remain visible in namespace v1.
Last edited on
@OP,

Could you do something like the following?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
template<typename T = bool, int VALUE = 0>
NewA{};

template<>
NewA<bool, int>
{
//current behavior
};

template<>
NewA<int, int SIZE>{
//new codes need value passed by SIZE
};

class A : public NewA<> {};
// or
typedef NewA<> A;
@doug4
The codes do not compile. same error as mine.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include <iostream>

struct A { A() { std::cout << "current behaviour\n" ; } };

template < typename, int, typename = void > struct A_new : A {};
template < int N = 0 > A_new() -> A_new<bool,N> ; // deduction guide

template < typename T, int N > // new behaviour if the type T is not bool
struct A_new< T, N, typename std::enable_if< !std::is_same<bool,T>::value >::type >
{ A_new() { std::cout << "new behaviour\n" ; } };

int main()
{
    A a1 ; // current behaviour (existing code)
    
    A_new a2 {} ; // current behaviour (uses deduction guide)
    A_new<bool,0> a3 ; // current behaviour
    
    A_new<int,0> a4 ; // new behaviour
    A_new<double,0> a5 ; // new behaviour
}

http://coliru.stacked-crooked.com/a/2b2e7695a4a50bbe
Thanks JLBorges. I might have to go with mbozzi's suggestion for the same reasons (my codebase is not in C++17 yet). However, your example is kind of what I was looking for.

I have issues to compile this code in ubuntu 16, though I noticed that your system seems ok.

g++ -std=c++17 -O3 -march=native -Wall -Wextra -pedantic-errors -Wno-unused-variable template_specialize.cpp -o test
template_specialize.cpp:6:49: error: expected constructor, destructor, or type conversion before ‘;’ token
template < int N = 0 > A_new() -> A_new<bool,N> ; // deduction guide
^
template_specialize.cpp: In function ‘int main()’:
template_specialize.cpp:16:11: error: missing template arguments before ‘a2’
A_new a2 {} ; // current behaviour (uses deduction guide)
Last edited on
> I have issues to compile this code in ubuntu 16

What does g++ --version print out?
g++ (Ubuntu 5.4.1-2ubuntu1~16.04) 5.4.1 20160904
Copyright (C) 2015 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
5.4 is an ancient version of the GNU compiler (the current version is 8.3);
for that code a compiler that actually supports C++17 is required.

This should work (C++11; no deduction guides; no class template deduction) with the legacy compiler.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include <iostream>

struct A { A() { std::cout << "current behaviour\n" ; } };

template < typename, int, typename = void > struct A_new : A {};
// template < int N = 0 > A_new() -> A_new<bool,N> ; // deduction guide // *** commented out

template < typename T, int N > // new behaviour if the type T is not bool
struct A_new< T, N, typename std::enable_if< !std::is_same<bool,T>::value >::type >
{ A_new() { std::cout << "new behaviour\n" ; } };

int main()
{
    A a1 ; // current behaviour (existing code)
    
    // A_new a2 {} ; // current behaviour (uses deduction guide) // *** commented out
    A_new<bool,0> a3 ; // current behaviour
    
    A_new<int,0> a4 ; // new behaviour
    A_new<double,0> a5 ; // new behaviour
}
This is exactly what I was looking for. I should have been able to go one step further by myself :-).

I think I need to study some new concepts. Not quite understand with that deduction guide.

Thank you very much for the help.
Thank you very much, JLBorges.
Topic archived. No new replies allowed.