Invalid use of incomplete type?

Here is a simplified version of the problem i'm facing in my code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
namespace 
{
  template <class T, class... Types>
   inline constexpr bool is_any_of = (std::is_same_v<T, Types> || ...);


  template<typename T = double,
           typename =
              std::enable_if_t<is_any_of<T,
                                   float, double, long double>>
   >
   class Complex
   {
     public:
       Complex() = default;
       void test();

     private:
       T m_r = T(),
       m_i   = T();

   };

template <typename T>
void Complex<T>::test() 
{} //ERROR HERE

}

int main()
{
Complex a;
}


When I define the test() method outside of the class, the compiler gives me a "invalid use of incomplete type" error, but it works fine when the function is defined inline. I am defining the entire class and the definitions in the same file, so why is it giving me this error?
Last edited on
you can't just say complex a. you have to give it a type.
complex <double> a; when you make a variable of the type, eg in main there...
Last edited on
jonnin wrote:
you can't just say complex a. you have to give it a type.


That's not correct. Omitting the template brackets when the type has a default is perfectly valid in C++17.

My problem is that I am getting an invalid use of incomplete type when I define test() outside of the class. If it were defined inline it works perfectly. I suspect it has something to do with the unnamed typename parameter I am using for SFINAE, but I am not sure why. Can you help me with this?
Last edited on
1
2
3
template <typename T, typename U>
void Complex<T, U>::test() 
{}
@Ganado

Huh, strange. I assumed if a type parameter didn't have a name it didn't need to be named in the member function definition outside of the class. This seems quite strange that you can leave it unnamed inside the class definition, but you have to give it a name outside. This means that Complex<T> is valid in the class but not outside of it. Weird. Anyway, thank you. Fixed.
Last edited on
To be honest I'm not sure of the formal rules here, but my gut feeling would say that you can't ignore one of the template parameters in the definition of the function template.

By the way, it seems you're trying to restrict the use of the Complex type to only be float, double, or long double, right?
A static_assert might be simpler here. And I imagine C++20 Concepts would help here and supersede static_assert, although I have not used Concepts yet in practice.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include <type_traits>

template <typename T = double>
class Complex {
    static_assert(std::is_floating_point<T>::value);

  public:
    Complex() = default;
};

struct Bogus { };

int main()
{
Complex a;
Complex<float> b;
//Complex<int> c; // error
//Complex<Bogus> c; // error
//Complex<float, float> c; // error
}


Or even better:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include <type_traits>

template <typename T = double>
class Complex {
    static_assert(std::is_floating_point<T>::value);

  public:
    Complex() = default;
};

struct Bogus { };

int main()
{
Complex a;
Complex<float> b;
//Complex<int> c; // error
//Complex<Bogus> d; // error
//Complex<float, float> e; // error
}
Last edited on
Ganado wrote:
To be honest I'm not sure of the formal rules here, but my gut feeling would say that you can't ignore one of the template parameters in the definition of the function template.


It seems that the rules are even weirder if you have an object of type Complex passed as a parameter or a return value. Here is what the out-of-class definition would look like:
1
2
3
template <typename T, typename U>
Complex<T> Complex<T, U>::test(Complex<T>&) 
{}


So in the case of a parameter or a return value, you have to use Complex<T> as normal. Complex<T,U> is only for the disambiguation of the member function. If you try to use Complex<T,U> as a return value or a parameter the compiler complains. Weird!
Topic archived. No new replies allowed.