Template constructor defined in the same header but outside the class is unidentified

Viewed 70

I know template class definitions should be defined in the header file. However, the constructor defined in the header but outside the class seems to be unnoticed by the compiler while the constructor defined inside the class works just fine. Am I missing something completely obvious?

This works

#include <type_traits>
#include <iostream>

struct A {
    template<typename T, 
             typename = typename std::enable_if<std::is_integral<T>::value>::type>
    A(T t) {
        this->t = static_cast<double>(t);
    }

    double t;
};

int main() {
    A a(3);
    std::cout << a.t << '\n';
}

This does not

#include <type_traits>
#include <iostream>

struct B {
    template<typename T, typename> B(T t);

    double t;
};

template<typename T, 
         typename = typename std::enable_if<std::is_integral<T>::value>::type>
B::B(T t) {
    this->t = static_cast<double>(t);
}

int main() {
    B b(3);
    std::cout << b.t << '\n';
}

saying

error: no matching function for call to 'B::B(int)'
     B b(3);
          ^
2 Answers

You forgot a few things. The defaulted template argument should be in the class declaration. And you'll need a typename added to that.

#include <type_traits>
#include <iostream>

struct B {
    template<typename T, typename = typename std::enable_if<std::is_integral<T>::value>::type> B(T t);

    double t;
};

template<typename T,
    typename>
    B::B(T t) {
    this->t = static_cast<double>(t);
}

int main() {
    B b(3);
    std::cout << b.t << '\n';
}

Yeah I think this is just a gcc bug. Filed 88864.

This is a shorter reproduction that should compile but doesn't (clang accepts):

struct B {
    template<typename T, typename U> B(T t);
};

template <typename T, typename U = int>
B::B(T t) { }

B b(3);
Related