In the code below, I am getting
main.cpp: undefined reference to `(anonymous namespace)::_result<int, double>::type
                                  PPP<int>::operator()<double>(double const&) const'
even though that template is explicitly instanciated. The code hase 3 modules: man.cpp uses PPP<type>, ppp.cpp explicit instanciates PPP<int> and PPP<double>, and aaa.cpp instanciates a method template.
Sorry for the lengthy test case, I couldn't get it shorter, and it appears the result_type template is needed for the fail.
ppp.h
#include <type_traits>
namespace
{
    template<typename T> struct _prio {};
    template<> struct _prio<int>    { using type = std::integral_constant<int,1>; };
    template<> struct _prio<double> { using type = std::integral_constant<int,2>; };
    template<typename A, typename X>
    struct _result
    {
        static constexpr bool cond = _prio<A>::type::value > _prio<X>::type::value;
        using type = typename std::conditional<cond, A, X>::type;
    };
} // ::anon
template<typename T>
struct PPP
{
    template<typename X>
    using result_type = typename _result<T,X>::type;
    T t;
    T operator () (const T&) const;
    // aaa.cpp contains an explicit instanciation for T=int, X=double
    // which is used in main().
    template<typename X>
    result_type<X> operator () (const X&) const;
};
// Instanciated in ppp.cpp
extern template struct PPP<int>;
extern template struct PPP<double>;
ppp.cpp
#include "ppp.h"
template<typename T>
T PPP<T>::operator () (const T& s) const
{
    return s + t;
}
template struct PPP<int>;
template struct PPP<double>;
aaa.cpp
#include "ppp.h"
template<class T>
template <class X>
auto PPP<T>::operator () (const X& x) const -> result_type<X>
{
    return x - (X) t;
}
extern template
auto PPP<int>::operator () (const double&) const -> result_type<double>;
template
auto PPP<int>::operator () (const double&) const -> result_type<double>;
main.cpp
#include "ppp.h"
#include <iostream>
extern template
auto PPP<int>::operator () (const double&) const -> result_type<double>;
int main (void)
{
    PPP<int> pi { 10 };
    std::cout << pi.t << std::endl;
    std::cout << pi (22) << std::endl;
    // Triggers with g++ v11.4, but not with clang++
    // main.cpp: undefined reference to `(anonymous namespace)::_result<int, double>::type
    //                                   PPP<int>::operator()<double>(double const&) const'
    std::cout << pi (33.3) << std::endl;
    return 0;
}
compile
$ <compiler> main.cpp ppp.cpp aaa.cpp -o main.x -Wall
Where <compiler> is one of g++ or clang++. With clang, it compiles and links fine, but with g++ v11.4 the linker complains
/usr/bin/ld: in function `main':
main.cpp: undefined reference to `(anonymous namespace)::_result<int, double>::type
                                  PPP<int>::operator()<double>(double const&) const'
collect2: error: ld returned 1 exit status
When I am adding -save-temps -dumpbase "" to g++ options, and then cat aaa.s | c++filt, the definition of the method can be seen, but it is neither .global nor .weak. And with -O2 the method is no more present. With clang++ it is .weak and thus visible.
So can someone explain what I am missing?
Aucun commentaire:
Enregistrer un commentaire