Чистым вариантом будет использование (неполиморфного) наследования для выполнения специализации без повторения всего:
namespace detail
{
template< typename T, bool a, bool b>
class TestImplBase
{
protected:
T value;
public:
TestImplBase() {}
TestImplBase( const T& val ) : value( val ) {}
void Set( const T& val ) { // [1]
value = val;
}
};
// General case
template< typename T, bool a, bool b>
class TestImpl : public TestImplBase<T, a, b>
{
public:
using TestImplBase<T, a, b>::TestImplBase; // keep the same constructors
using TestImplBase<T, a, b>::Set; // See comment by Jarod42
// Has [1] as well.
void Set( const float val ) { // [2] To run just for T != float
//...
}
};
// Specialization for T == float
template<bool a, bool b>
class TestImpl<float, a, b> : public TestImplBase<float, a, b>
{
public:
using TestImplBase<float, a, b>::TestImplBase; // keep the same constructors
// Only has [1], not [2].
};
}
template< typename T, bool a, bool b>
using Test = detail::TestImpl<T, a, b>;
https://godbolt.org/z/zRieA2
Это очень общий подход, возможно,Слишком общий для вашего случая, но это трудно сказать по этому небольшому куску кода.