mercredi 20 juillet 2022

SFINAE unresolved external symbol when putting definition in src file

I have the following preprocessor class, for which I would like to have separate implementations for Real or complex data.

PreProcessor.cuh

#ifndef __PREPROCESSOR_TEST_CUH__
#define __PREPROCESSOR_TEST_CUH__

#include <cuda/std/complex>
#include <iostream>

#define DEFINITION_IN_HEADER 1 // change between definition in src or header file

typedef cuda::std::complex<float> ccfloat;
typedef cuda::std::complex<double> ccdouble;

template <template <class...> class TT, class... Args>
std::true_type is_tt_impl(TT<Args...>);
template <template <class...> class TT>
std::false_type is_tt_impl(...);

// use as is_tt<cuda::std::complex, Q>::value
template <template <class...> class TT, class T>
using is_tt = decltype(is_tt_impl<TT>(std::declval<typename std::decay<T>::type>()));

template <typename Tin, typename Tout>
class PreProcessor
{
  public:
    // specialization for complex input
    template <typename Q = Tin>
    typename std::enable_if_t<is_tt<cuda::std::complex, Q>::value, void> run();

    // specialization for real input
    template <typename Q = Tin>
    typename std::enable_if_t<!is_tt<cuda::std::complex, Q>::value, void> run();
};

#if DEFINITION_IN_HEADER
// specialization for complex input
template <typename Tin, typename Tout>
template <typename Q>
typename std::enable_if_t<is_tt<cuda::std::complex, Q>::value, void> PreProcessor<Tin, Tout>::run()
{
    std::cout << "COMPLEX template." << std::endl;
}

// specialization for real input
template <typename Tin, typename Tout>
template <typename Q>
typename std::enable_if_t<!is_tt<cuda::std::complex, Q>::value, void> PreProcessor<Tin, Tout>::run()
{
    std::cout << "REAL template." << std::endl;
}
#endif

#endif //!__PREPROCESSOR_TEST_CUH__

If I define the respective implementations in the header file, all is good. But when I define them in a source file (i.e. DEFINITION_IN_HEADER =0):

PreProcessor.cu

#include "PreProcessor.cuh"

#if !DEFINITION_IN_HEADER

// specialization for complex input
template <typename Tin, typename Tout>
template <typename Q>
typename std::enable_if_t<is_tt<cuda::std::complex, Q>::value, void> PreProcessor<Tin, Tout>::run()
{
    std::cout << "COMPLEX template." << std::endl;
}

// specialization for real input
template <typename Tin, typename Tout>
template <typename Q>
typename std::enable_if_t<!is_tt<cuda::std::complex, Q>::value, void> PreProcessor<Tin, Tout>::run()
{
    std::cout << "REAL template." << std::endl;
}

// instantiation
template class PreProcessor<ccfloat, ccfloat>;
template class PreProcessor<int, int>;

#endif

I get the following error:

[build] main.obj : error LNK2019: unresolved external symbol "public: void __cdecl PreProcessor<class cuda::std::__4::complex<float>,class cuda::std::__4::complex<float> >::run<class cuda::std::__4::complex<float> >(void)" (??$run@V?$complex@M@__4@std@cuda@@@?$PreProcessor@V?$complex@M@__4@std@cuda@@V1234@@@QEAAXXZ) referenced in function "public: void __cdecl Processor<class cuda::std::__4::complex<float>,class cuda::std::__4::complex<float> >::run(void)" (?run@?$Processor@V?$complex@M@__4@std@cuda@@V1234@@@QEAAXXZ)

Or, a bit more readable when I use Processor<int, int> Preal;. What is going on, can I not move SFINAE template speciliazations to src files?

[build] main.obj : error LNK2019: unresolved external symbol "public: void __cdecl PreProcessor<int,int>::run<int>(void)" (??$run@H@?$PreProcessor@HH@@QEAAXXZ) referenced in function "public: void __cdecl Processor<int,int>::run(void)" (?run@?$Processor@HH@@QEAAXXZ)

My main:

main.cu


#include "cuda_runtime.h"
#include "device_launch_parameters.h"
#include <cuda.h>
#include <cuda/std/complex>

#include "PreProcessor_test.cuh"

template <typename Tin, typename Tout>
class Processor
{
  public:
    PreProcessor<Tin, Tout> *Pp;
    Processor() { Pp = new PreProcessor<Tin, Tout>; }
    ~Processor() { delete Pp; }
    void run() { Pp->run(); }
};

int main()
{
    Processor<int, int> Preal;
    Preal.run();

    using ccfloat = cuda::std::complex<float>;
    Processor<ccfloat, ccfloat> Pcomplex;
    Pcomplex.run();
    return 0;
}

Aucun commentaire:

Enregistrer un commentaire