Задать вопрос
@Vadimatorikda
Инженер-программист, embedded разработчик

Выбор типа переменной класса в зависимости от параметра шаблона (C++17, if constexpr)?

Имеется шаблон класса. Он принимает параметр enum class. Требуется в зависимости от выбранного параметра создать переменную заданного размера. Пример того, как я себе это представлял:
template < EC_SPI_CFG_DATA_FRAME FRAMES >
class spi {
    constexpr spi() {};
    if constexpr ( FRAMES == EC_SPI_CFG_DATA_FRAME::FRAME_8_BIT ) {
        mutable uint8_t* p_tx = nullptr;
    } else {
        mutable uint16_t* p_tx = nullptr;
    }
};

Однако получаю следующее:
spi.h:137: ошибка: expected unqualified-id before 'if'
     if constexpr ( FRAMES == EC_SPI_CFG_DATA_FRAME::FRAME_8_BIT ) {
     ^~
spi.h:139: ошибка: expected unqualified-id before 'else'
     } else {
       ^~~~

В параметрах компиляции C++ файла стоит флаг -std=c++1z.
  • Вопрос задан
  • 640 просмотров
Подписаться 2 Оценить 3 комментария
Решение пользователя Евгений Шатунов К ответам на вопрос (3)
@MarkusD Куратор тега C++
все время мелю чепуху :)
Ты можешь добиться желаемого используя частную специализацию, например.

Суть такова. Нужно превратить значения типа перечисления в тип. Сделать мы это можем используя возможность указывать в качестве параметра шаблона значения перечислимых типов.

Например:
enum class AllowedTypes : uint8_t
{
	Int8	= 0,
	Uint8,
	Int16,
	Uint16,
};

template< AllowedTypes TYPE >
struct AllowedType;


А для того, чтобы конкретное значение перечисления правильно переводилось в тип, шаблон "AllowedType" нужно специализировать.
spoiler
template<>
struct AllowedType<AllowedTypes::Int8>
{
	using Type = int8_t;
};

template<>
struct AllowedType<AllowedTypes::Uint8>
{
	using Type = uint8_t;
};

template<>
struct AllowedType<AllowedTypes::Int16>
{
	using Type = int16_t;
};

template<>
struct AllowedType<AllowedTypes::Uint16>
{
	using Type = uint16_t;
};


После этого достаточно использовать "typename AllowedType::Type" в нужном тебе месте.
spoiler
template< AllowedTypes TYPE >
struct spi
{
	typename AllowedType<TYPE>::Type*	p_tx = nullptr;
	
	constexpr spi() {};
};


Вот пример работы:
spoiler
// Example program
#include <typeinfo>
#include <iostream>
#include <string>
#include <cstdint>

enum class AllowedTypes : uint8_t
{
	Int8	= 0,
	Uint8,
	Int16,
	Uint16,
};

template< AllowedTypes TYPE >
struct AllowedType;

template<>
struct AllowedType<AllowedTypes::Int8>
{
	using Type = int8_t;
};

template<>
struct AllowedType<AllowedTypes::Uint8>
{
	using Type = uint8_t;
};

template<>
struct AllowedType<AllowedTypes::Int16>
{
	using Type = int16_t;
};

template<>
struct AllowedType<AllowedTypes::Uint16>
{
	using Type = uint16_t;
};

template< AllowedTypes TYPE >
using TypeFor = typename AllowedType<TYPE>::Type;


template< AllowedTypes TYPE >
struct spi
{
	TypeFor<TYPE>*	p_tx = nullptr;
	
	constexpr spi() {};
};

int main()
{
	spi<AllowedTypes::Int8> spi1;
	std::cout << typeid( *spi1.p_tx ).name() << " " << sizeof( *spi1.p_tx ) << std::endl;
	
	spi<AllowedTypes::Uint16> spi2;
	std::cout << typeid( *spi2.p_tx ).name() << " " << sizeof( *spi2.p_tx ) << std::endl;
	
	return 0;
}

cpp.sh/85p6
Ответ написан