Почему специализация шаблонов не работает в gcc - PullRequest
3 голосов
/ 29 мая 2019

Я хотел бы написать методы списков типов для работы с микроконтроллерами GPIO.

Я хотел бы создать список GPIO и выбирать только выводы определенного порта.Итак, шаблон GetPinWithPort имеет специализацию, которая проверяет предоставленный тип.

template <typename... Ts>
struct tlist
{
    using type = tlist;
};

template <typename T> class debug_t;

#define MAKE_PORT(NAME, ID)\
    class NAME\
    {\
        public:\
        static void Set(uint32_t v) { };\
        static void Reset(uint32_t v) { };\
        enum { id = ID };\
    };

MAKE_PORT(Porta, 'A');
MAKE_PORT(Portb, 'B');

template <class PORT, uint8_t PIN>
class TPin
{
public:
    static void Set() { PORT::Set(1 << PIN); }
    static void Reset() { PORT::Reset(1 << PIN); }

    typedef PORT port;
    enum { pin = PIN };
};

template <class TPort, class T>
struct GetPinWithPort {
    using type = tlist<>;
};

template <typename TPort, uint32_t N>
struct GetPinWithPort<TPort, TPin<TPort, N>>
{
    using type = TPin<TPort, N>;
};

int main()
{

    using pina = GetPinWithPort<Porta, TPin<Porta, 1> >::type;

    // std::cout << typeid(pina).name() << std::endl;  //Visual Studio gives: class TPin<class Porta,1>
    debug_t<pina> d; //gcc output: tlist<>

}

Visual Studio дает ожидаемый результат.Но gcc - пустой список.Что здесь не так?

Ответы [ 2 ]

2 голосов
/ 29 мая 2019

должно быть

template <typename TPort, uint8_t N>  // or auto
struct GetPinWithPort<TPort, TPin<TPort, N>>

не

template <typename TPort, uint32_t N>
struct GetPinWithPort<TPort, TPin<TPort, N>>

потому что (я не адвокат по языку, просто я так понимаю):

template <class PORT, uint8_t PIN>
class TPin {}
// and 
using pina = GetPinWithPort<Porta, TPin<Porta, 1> >::type;

В специализации gcc нужно выбирать между:

class T

и

TPin<TPort, uint32_t>

и его тип:

TPin<Porta, 1>

Так что, возможно, gcc разрешит TPin<Porta, 1> до TPin<Porta, uint8_t>, а затем провалит специализацию.

1 голос
/ 29 мая 2019

В этой строке using pina = GetPinWithPort<Porta, TPin<Porta, 1> >::type; 1 имеет тип int, а не uint32_t.Таким образом, вы создаете экземпляр GetPinWithPort<Porta, int> (неспециализированное определение), а не GetPinWithPort<Porta, uint32_t>.

Вот как должна выглядеть специализация для передачи нужного параметра шаблона в TPin:

template <typename TPort, uint8_t N>
struct GetPinWithPort<TPort, TPin<TPort, N>>
{
    using type = TPin<TPort, N>;
};

Вот как это следует использовать:

using pina = GetPinWithPort<Porta, TPin<Porta, static_cast<uint8_t>(1)> >::type;

Причина этого заключается в том, что C ++ очень строго относится к использованию типов вместо шаблонов: допускается очень ограниченное преобразование типов.

...