Can CTAD be used inside a member of the template class?

128 Views Asked by At

C++ has this helpful feature that says that the template parameter is implicit in the code inside a template class A. However, for construction, this seems to clash with CTAD.

How can I make CTAD take precedence?

For example, here, there is an error in the f member because A is interpreted as A<T> where T is std::string, and not deduced from the parameter double.

#include<string>

template<class T>
struct A {
    A(T const& t) {}
    auto f() {return A{5.0};}  // error here triggered by line 11 `auto a2 = a1.f();`
};

int main() {
    A a1{std::string{"hello"}};
    auto a2 = a1.f();
}

https://godbolt.org/z/3nc7nev3o

2

There are 2 best solutions below

8
NathanOliver On BEST ANSWER

You need to use ::A to tell the compiler to use the name A from the global scope instead of using the name A in the class scope which is just shorthand for A<T>. That gives you:

#include<string>

template<class T>
struct A {
    A(T const& t) {}
    auto f() {return ::A{5.0};}  // uses CTAD to return A<double>
};

int main() {
    A a1{std::string{"hello"}};
    auto a2 = a1.f();
}

as seen in this live example.


Another option is to add a private alias to the class type and then use that alias in the function as needed. That gives you:

#include<string>

template<class T>
struct A {
private:
    template <typename U>
    using NewA = A<U>;
public:
    A(T const& t) {}
    auto f() {return NewA{5.0};}  // uses CTAD to return A<double>
};

int main() {
    A a1{std::string{"hello"}};
    auto a2 = a1.f();
}

and can bee seen working here

0
alfC On

It seems I can define a template typedef and hope the CTAD works through it.

#include<string>

template<class T>
struct A;

template<class T> using A_CTAD = A<T>;

template<class T>
struct A {
    A(T const& t) {}
    auto f() {return A_CTAD{5.0};}  // error here triggered by line 11 `auto a2 = a1.f();`
};

int main() {
    A a1{std::string{"hello"}};
    auto a2 = a1.f();
}

https://godbolt.org/z/hex79s91a

but it doesn't seem to be a big gain compared to using the good old make function. https://godbolt.org/z/j3PTW7MWY


Version 2, make an internal template typedef, not bad. No need for forward declarations.

template<class T>
struct A {
    A(T const& t) {}
private:
    template<class TT> using CTAD = A<TT>;
public:
    auto f() {return CTAD{5.0};}  // error here triggered by line 11 `auto a2 = a1.f();`
};