Suppose I have the following code:
enum class Type
{
Type32,
Type64
};
template<Type T>
class MyClass
{
public:
using MyType = typename std::conditional<T == Type::Type32, uint32_t, uint64_t>::type;
MyType getSum()
{
MyType sum = 0;
for(size_t i = 0;i < sizeof(arr);i )
{
sum = arr[i];
}
return sum;
}
private:
//MyType arr[4] = { 0x1234, 0x5678, 0x9ABC, 0xDEF0 }; // for Type::Type32
//MyType arr[2] = { 0x12345678, 0x9ABCDE }; // for Type::Type64
};
I try to initialize a class variable depends on the template type with the same name but different type and value. How can I do that? I probably looking for a solution that works in c 11.
CodePudding user response:
Here is a simple way:
#include <array>
#include <cstdint>
#include <type_traits>
enum class Type { Type32, Type64 };
template <Type>
struct As128Bits;
template <>
struct As128Bits<Type::Type32> {
using Integer = std::uint32_t;
std::array<Integer, 4> data{0x1234, 0x5678, 0x9ABC, 0xDEF0};
};
template <>
struct As128Bits<Type::Type64> {
using Integer = std::uint64_t;
std::array<Integer, 2> data{0x12345678, 0x9ABCDE};
};
template <Type T>
struct MyClass : private As128Bits<T> {
using Integer = typename As128Bits<T>::Integer;
using As128Bits<T>::data;
Integer getSum() {
Integer sum = 0;
for (auto const val : data) {
sum = val;
}
return sum;
}
};
CodePudding user response:
you can move different part into separate class and do specialization. (or you can do full class specialization if it fits)
template <Type T>
struct MyData;
template <>
struct MyData<Type::Type32>{
uint32_t arr[4] = { 0x1234, 0x5678, 0x9ABC, 0xDEF0 };
};
template <>
struct MyData<Type::Type64>{
uint64_t arr[2] = { 0x12345678, 0x9ABCDE };
};
template<Type T>
class MyClass: private MyData<T>{
// common functions
};
CodePudding user response:
You can use tag dispatch (with a delegating constructor):
template<Type T>
class MyClass
{
public:
using MyType = typename std::conditional<T == Type::Type32, uint32_t, uint64_t>::type;
// This will call one of the constructors below
MyClass() : MyClass(std::integral_constant<Type, T>{}) {}
MyType getSum() { /* ... */ }
private:
explicit MyClass(std::integral_constant<Type, Type::Type32>) : arr{ 0x1234, 0x5678, 0x9ABC, 0xDEF0 } {}
explicit MyClass(std::integral_constant<Type, Type::Type64>) : arr{ 0x12345678, 0x9ABCDEF0 } {}
MyType arr[T == Type::Type32 ? 4 : 2];
};
CodePudding user response:
This is how you could do it, using a helper lambda function to determine the array type and initialize it :
#include <array>
#include <numeric>
#include <type_traits>
enum class Type
{
Type32,
Type64
};
// Create a lambda function template
// if constexpr will select the right array type to return and initializes it.
template<Type T>
auto arr_initializer = []
{
if constexpr (T == Type::Type32)
{
return std::array<uint32_t, 4>{0x1234, 0x5678, 0x9ABC, 0xDEF0};
}
if constexpr (T == Type::Type64)
{
return std::array<uint64_t, 2>{ 0x12345678, 0x9ABCDE };
}
};
template<Type T>
class MyClass
{
public:
using MyType = typename std::conditional<T == Type::Type32, uint32_t, uint64_t>::type;
MyClass() :
arr{ arr_initializer<T>() }
{
};
MyType getSum()
{
// no raw loops (if possible)
return std::accumulate(arr.begin(), arr.end(), 0);
}
private:
// arr should be of the type returned by arr_initializer lambda
decltype(arr_initializer<T>()) arr;
};
int main()
{
MyClass<Type::Type32> c32;
MyClass<Type::Type64> c64;
auto val32 = c32.getSum();
auto val64 = c64.getSum();
return val32;
}