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

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 the simplest integer enumeration.

I would like to apply 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);

      

<s> I am getting error

error: expected ')' before 'pin_tx'

      

Why is this syntax illegal? EDIT :typename

Now it gives me this error when I try to 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'

      

+3


source to share


1 answer


Template parameters used in function arguments are not deduced because the arguments are of dependent types.

"But this is stupid!" you would say; "Obviously N is 1! Why can't the compiler do this?"

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

both usart<1>::tx

are the same type.

The compiler cannot know what N should be without checking that only one instance of usart is of the exact type as the member tx

. This would require too many instances or too complex logic to prove that no amount of instantiation would result in what is in the general case. Of course, it would be easy to implement something for this specific case, but this is not very useful for all other cases. The C ++ committee simply decided not to require this from the compiler authors.

+14


source







All Articles