0

I'm currently stumped by a IMHO strange problem: Using a template breaks compilation, where using a typedef works just fine. The function I'm writing is intended to determine the Analytic Signal from a real valued time series with the following signature

#ifndef USE_TEMPLATE
typedef sample_t sample_T
#else
template<typename sample_T>
#endif
analytic_err analytic(
    size_t length,
    sample_T const * const signal,
    sample_T * const amplitude,
    sample_T * const phase )
{
    typedef kissfft<sample_T> kissfft_t;
    /* ... */

kissfft is the C++ variant of the KissFFT fast fourier transform library. A few lines further I allocate some work area arrays.

    kissfft_t::cpx_type *inout = new kissfft_t::cpx_type[padded_length];

I'm deliberately not using a std::vector and I did also modify kissfft.hh to be STL-less. I don't want to discuss the use or disuse of STL. In this project the STL is a no-go (not my decision).

And that's where the trouble starts. If I don't use the template variant, i.e. define a typedef from sample_t to sample_T everything works just fine and the resulting program passes all the test cases.

Trouble starts as soon as I switch to the use of templates:

Both GCC and Clang bail out with some error I am unable to make sense of:

GCC error

In file included from /home/dw/extradev/octuda/src/hilbert_test.cc:6:0:
signalprocess.cc: In function ‘analytic_err analytic(size_t, const sample_T*, samplT*, sample_T*)’:
signalprocess.cc:54:23: error: ‘inout’ was not declared in this scope
signalprocess.cc:54:35: error: expected type-specifier
signalprocess.cc:54:35: error: expected ‘;’
signalprocess.cc: In instantiation of ‘analytic_err analytic(size_t, const sample_T sample_T*, sample_T*) [with sample_T = float; analytic_err = analytic_err_t; size_t = long unsigned int]’:
test_analytic.cc:45:41:   required from here
signalprocess.cc:54:2: error: dependent-name ‘kissfft_t:: cpx_type’ is parsed as a n-type, but instantiation yields a type
signalprocess.cc:54:2: note: say ‘typename kissfft_t:: cpx_type’ if a type is meant
signalprocess.cc:59:2: error: dependent-name ‘kissfft_t:: cpx_type’ is parsed as a n-type, but instantiation yields a type
signalprocess.cc:59:2: note: say ‘typename kissfft_t:: cpx_type’ if a type is meant

Clang error

In file included from ../../src/hilbert_test.cc:6:
signalprocess.cc:54:23: error: use of undeclared identifier 'inout'
        kissfft_t::cpx_type *inout = new kissfft_t::cpx_type[padded_length];
                             ^
signalprocess.cc:54:35: error: expected a type
        kissfft_t::cpx_type *inout = new kissfft_t::cpx_type[padded_length];
                                         ^
signalprocess.cc:55:6: error: use of undeclared identifier 'inout'
        if(!inout) {
            ^

and some more all following the same gist.

GCC and Clang to agree that something is not right when using templates. So what am I doing wrong here?

datenwolf
  • 159,371
  • 13
  • 185
  • 298

2 Answers2

3

When you're using template, then this

kissfft_t::cpx_type *inout = new kissfft_t::cpx_type[padded_length];

should become this:

typename kissfft_t::cpx_type *inout = new typename kissfft_t::cpx_type[padded_length];
^^^^^^^^note                              ^^^^^^^^note

Because kissfft_t depends on the template argument, and as such cpx_type is a dependent type, hence you need to use typename to disambiguate it from static value.

To know in detail as to why typename is required, see this topic:

Community
  • 1
  • 1
Nawaz
  • 353,942
  • 115
  • 666
  • 851
1

If sample_T is a template parameter, then kissfft_t::cpx_type is a dependent name. The compiler cannot deduce that it is a typename until the template is instantiated, so it needs to be written as typename kissfft_t::cpx_type.

If it isn't a template parameter, then putting typename there is an error, so unfortunately you'll need to add more hideous preprocessor shenanigans in order to do the right thing whether or not USE_TEMPLATE is defined.

Mike Seymour
  • 249,747
  • 28
  • 448
  • 644