Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why can't the template parameters for enums nested in a template class be deduced?

I have some constants named like this:

template<int n> class usart {
private:
    usart();
public:
    enum class tx {};
    enum class rx {};
    enum class ck {};
};

template<> class usart<1> {
public:
    enum class tx { A9  = gpio::A9,  C4 = gpio::C4 };
    enum class rx { A10 = gpio::A10, C5 = gpio::C5 };
    enum class ck { A8  = gpio::A8 };
};

// two more of these

where gpio is just a simple integer enum.

I'd like to enforce some type safety on my class in another file:

class USART {
public:
    template<int N>
    USART(typename usart<N>::tx pin_tx, typename usart<N>::rx pin_rx) {
        //This signature enforces correct pins with types, doesn't it?
    }
};

However, when I use this with

USART us = USART(usart<1>::tx::A9, usart<1>::rx::A10);

I get the error

error: expected ')' before 'pin_tx'

Why is this syntax illegal? EDIT: typename

This now gives me this error when I try and instantiate the class:

error: no matching function for call to 'USART::USART(usart<1>::tx, usart<1>::rx)'
note: template<int N> USART::USART(typename usart<N>::tx, typename usart<N>::rx)
note:   template argument deduction/substitution failed:
note:   couldn't deduce template parameter 'N'
like image 976
Eric Avatar asked Dec 07 '22 09:12

Eric


1 Answers

The template parameters used in the function arguments are not deducible because the the arguments are of dependent types.

"But that's silly!" you would say; "It is obvious that N is 1! Why can't the compiler have the smarts to deduce that?"

Consider the following:

template<> class usart<4321> {
public:
    typedef usart<1>::tx tx;
    typedef usart<1>::rx rx;
    typedef usart<1>::ck ck;
};

Should N be 1 or 4321? After all, usart<4321>::tx and usart<1>::tx are the same type.

The compiler cannot know what N should be without checking that only one instantiation of usart has that exact type as the tx member. This would either require too many instantiations or way too complex logic to prove that no instantiation would result in that in the general case. Sure, it might be simple to implement something for this particular case, but that isn't terribly useful for all other cases. The C++ committee simply decided to not require this of compiler writers.

like image 141
R. Martinho Fernandes Avatar answered Dec 09 '22 13:12

R. Martinho Fernandes