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.
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;
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)
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.