模板特化:参数不同于 T 的成员函数
Template specialisation: member function with parameter different from T
是否可以使用模板特化来实现类似下面的内容?
#include <iostream>
template< typename T, bool a, bool b>
class Test
{
T value;
public:
Test() {}
Test( const T& val ) : value( val ) {}
void Set( const T& val ) { // [1]
value = val;
}
void Set( const float val ) { // [2] To run just for T != float
...
}
};
int main()
{
Test<int, true, true> test1;
test1.Set( 1234 ); // Run [1]
Test<float, true, true> test2;
test2.Set( 1.234f ); // Run [1]
Test<int, true, true> test3;
test3.Set( 1.234f ); // Run [2]
}
当T
与float
不同时,是否有语法指定成员函数是要选择的成员函数?
一个干净的选择是使用(非多态)继承来进行专业化而不重复所有内容:
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>;
这是一种非常通用的方法,对于您的情况可能有点过于通用,但是从这一小段代码很难说出来。
Is it possible to implement something like what follows using template specialisation?
是:专门化完整 class Test
:通用案例,有“[2]”,float
案例,没有它。
否则我想你可以使用 SFINAE 在 T
为 float
时禁用“[2]”
template <typename U = T>
std::enable_if_t<false == std::is_same_v<U, float>> Set( const float val )
{ /* ... */ }
或者也可能
template <typename U = T>
std::enable_if_t<false == std::is_same_v<U, float> && true == std::is_same_v<U, T>>
Set( const float val )
{ /* ... */ }
如果您想避免启用 Set()
,在 float
的情况下,说明 U
模板类型。
使用 C++20,这将非常简单:
requires
允许 "discard" 方法:
template <typename T, bool a, bool b>
class Test
{
T value;
public:
Test() {}
Test(const T& val) : value( val ) {}
void Set(const T& val) { value = val; }
void Set(float val) requires (!std::is_same<T, float>::value) {
// ...
}
};
否则SFINAE一般是去除重载的方法(但是需要模板函数,所以你必须制作一个你的方法模板)。
是否可以使用模板特化来实现类似下面的内容?
#include <iostream>
template< typename T, bool a, bool b>
class Test
{
T value;
public:
Test() {}
Test( const T& val ) : value( val ) {}
void Set( const T& val ) { // [1]
value = val;
}
void Set( const float val ) { // [2] To run just for T != float
...
}
};
int main()
{
Test<int, true, true> test1;
test1.Set( 1234 ); // Run [1]
Test<float, true, true> test2;
test2.Set( 1.234f ); // Run [1]
Test<int, true, true> test3;
test3.Set( 1.234f ); // Run [2]
}
当T
与float
不同时,是否有语法指定成员函数是要选择的成员函数?
一个干净的选择是使用(非多态)继承来进行专业化而不重复所有内容:
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>;
这是一种非常通用的方法,对于您的情况可能有点过于通用,但是从这一小段代码很难说出来。
Is it possible to implement something like what follows using template specialisation?
是:专门化完整 class Test
:通用案例,有“[2]”,float
案例,没有它。
否则我想你可以使用 SFINAE 在 T
为 float
template <typename U = T>
std::enable_if_t<false == std::is_same_v<U, float>> Set( const float val )
{ /* ... */ }
或者也可能
template <typename U = T>
std::enable_if_t<false == std::is_same_v<U, float> && true == std::is_same_v<U, T>>
Set( const float val )
{ /* ... */ }
如果您想避免启用 Set()
,在 float
的情况下,说明 U
模板类型。
使用 C++20,这将非常简单:
requires
允许 "discard" 方法:
template <typename T, bool a, bool b>
class Test
{
T value;
public:
Test() {}
Test(const T& val) : value( val ) {}
void Set(const T& val) { value = val; }
void Set(float val) requires (!std::is_same<T, float>::value) {
// ...
}
};
否则SFINAE一般是去除重载的方法(但是需要模板函数,所以你必须制作一个你的方法模板)。