TmsKtel
TmsKtel

Reputation: 371

C++ template deduction couldn't infer template argument

I have the following scenario:

struct AP;
struct B
{
    B() : m(2) {}
    int m;
};

struct A : private B
{
    A() : B(), n(1) {}
private:
    int n;
    friend AP;
};

struct AP
{
    AP(A& a) : a_(a) {}

    template<typename T>
    struct A_B {
        using type = typename std::enable_if< std::is_base_of< typename std::remove_reference<T>::type,
                                                               A >::value,
                                                                    T >::type;
    };

    template<typename T>
    operator typename A_B<T>::type()
    {
        return static_cast<T>(a_);
    }

    template<typename T>
    typename A_B<T>::type get()
    {
        return static_cast<T>(a_);
    }

    int& n() { return a_.n; }
private:
    A& a_;
};

int main()
{
    A a;
    AP ap(a);
    ap.n() = 7;
    const B& b = ap.get<const B&>();
    //const B& b = ap; candidate template ignored: couldn't infer template argument 'T'
    //auto b = static_cast<const B&>(ap); candidate template ignored: couldn't infer template argument 'T'
    std::cout<<b.m;
}

The commented lines wouldn't compile. Clang++ notes that "candidate template ignored: couldn't infer template argument 'T'"

Why am I not able to get a reference to A's base with the cast operator? I think the code would look much nicer that way.

Upvotes: 3

Views: 1635

Answers (2)

AndyG
AndyG

Reputation: 41092

The answer that you posted works, but is overkill unless you really want a static_assert message.

Classic templating works just fine in this instance because A is already convertible to B:

struct AP
{
    AP(A& a) : a_(a) {}

    template<typename T>
    operator T()
    {
        return a_;
    }

    template<typename T>
    T get()
    {
        return a_;
    }

    int& n() { return a_.n; }
private:
    A& a_;
};

Demo

Upvotes: 1

TmsKtel
TmsKtel

Reputation: 371

I found the answer here: http://www.mersenneforum.org/showthread.php?t=18076

This is the key: "when you want the compiler to deduce argument types, those types must not be dependent types"

With this it compiles:

template<typename T>
operator T()
{
    static_assert(std::is_base_of< typename std::remove_reference<T>::type,A >::value,
                        "You may cast AP only to A's base classes.");
    return static_cast<T>(a_);
}

Upvotes: 0

Related Questions