"Invalid Use of Incomplete Type" Error With Partial Template Specialization

invalid use of incomplete type error with partial template specialization

You can't partially specialize a function. If you wish to do so on a member function, you must partially specialize the entire template (yes, it's irritating). On a large templated class, to partially specialize a function, you would need a workaround. Perhaps a templated member struct (e.g. template <typename U = T> struct Nested) would work. Or else you can try deriving from another template that partially specializes (works if you use the this->member notation, otherwise you will encounter compiler errors).

Invalid use of incomplete type for partial template specialization c++

You can explicitly specialize a member function of a particular implicit instantiation of a class template. But this is not allowed with partial specializations. If you don't want to write a full partial specialization, you can consider using tag dispatch:

private:
void foo(std::true_type /*value_is_string*/) const { /* "partial" */ }
void foo(std::false_type /*value_is_string*/) const { /* "base" */ }

public:
void foo() const { return foo(std::is_same<Value, std::string>()); }

or refactoring foo() into a base class template that you partially specialize.

Template class and 'invalid use of incomplete type' error

You can apply SFINE(i.e."Substitution Failure Is Not An Error") technique along with function overloading to choose the correct method when T is std::complex in Matrix<T> class instatiation.

Following is the demonstration of the idea: (See example code online live)

#include <type_traits>  // std::enable_if, std::false_type

// traits for checking, T is `std::complex`
template<typename> struct is_std_complex : std::false_type {};
template<typename T> struct is_std_complex<std::complex<T>> : std::true_type {};

// traits for `std::enable_if` helpers
template<typename Type, typename ReType = void>
using EnabledForComplex = typename std::enable_if<is_std_complex<Type>::value, ReType>::type;

template<typename Type, typename ReType = void>
using EnabledNotForComplex = typename std::enable_if<!is_std_complex<Type>::value, ReType>::type;

template<typename T>
class Matrix
{
// ...members

public:
template<typename Type = T>
auto is_hermitian() const -> EnabledNotForComplex<Type, bool>
{
// ... code for non-std::complex types
}

template<typename Type = T>
auto is_hermitian() const->EnabledForComplex<Type, bool>
{
// ... code for std::complex types
}
};

That being said, if you have access to c++17, you could use if constexpr, which will only instantiate the branch, which is true for the case at compile time. (See example code online live)

#include <type_traits> // std::false_type

// traits for checking, T is `std::complex`
template<typename> struct is_std_complex : std::false_type {};
template<typename T> struct is_std_complex<std::complex<T>> : std::true_type {};

template<typename T>
class Matrix
{
// ...members

public:
bool is_hermitian() const
{
if (!is_squared()) return false;
if constexpr (is_std_complex<T>::value)
{
// ... code for std::complex types
}
else
{
// ... code for non-std::complex types
}
return true;
}
};

Partial template specialization, invalid use of incomplete type

Partial template specialization only applies to the entire class template. You can't partially specialize just one member.

One solution is to introduce a base class and specialize that instead.

#include <future>

template< typename T >
struct Foo_base {
static void _call(std::function<T ()> &f, std::promise<T> &p) {
p.set_value(f());
}
};

template<>
struct Foo_base< void > {
static void _call(std::function<void ()> &f, std::promise<void> &p)
{
f();
p.set_value();
}
};

template <typename A, typename T>
class Foo : Foo_base< T >
{
private:
using Foo::Foo_base::_call;
std::function<T ()> _f;
std::promise<T> _p;

public:
Foo(std::function<T ()> x) : _f(x) {}

void set_promise() {
_call(_f, _p);
}
};

Invalid use of incomplete type (chained templated classes)

The problem is that in certain places of code your classes are really incomplete.

According to [class.mem]/1:

A class is considered a completely-defined object type (3.9) (or complete type) at the closing } of the class-specifier.
Within the class member-specification, the class is regarded as complete within function bodies,
default arguments, using-declarations introducing inheriting constructors (12.9), exception-specifications, and
brace-or-equal-initializers for non-static data members (including such things in nested classes). Otherwise
it is regarded as incomplete within its own class member-specification.

When applied to your code, this means in particular that the class is incomplete within function parameter lists. Now let's look at the definition of DDirectory::foo():

template<class arg,class conv>
struct DDirectory : public virtual Directory<arg,conv>, public virtual DFile<arg,conv>{
void foo(typename conv::Directory::UnionType& d){
}
};

In the instantiation DDirectory<int,thing> conv is FSU<int,DFS,DFS>, so instantiation of it involves instantiation of UnionBases inside, and eventially to this:

static_assert(AllInheritFrom<Base,Rest...>::value, "All of the elements of UnionBase must have Base as a public base");

where one of classes is DDirectory<int,thing>. Remember, all this happens in the deducing the type of the parameter of foo(), so DDirectory<int,thing> is incomplete, and that's what the compiler is saying.

You could try to move that static_assert for example to the constructor of UnionBase, but it doesn't solve other error which I think is impossible to fix, and the reason is the same:

error: invalid application of 'sizeof' to an incomplete type 'DDirectory<int, FSU<int, DFS, DFS> >'
static const bool FirstBigger = sizeof(First) > sizeof(Best);
^~~~~~~~~~~~~

Here is a minimized example reproducing the problem:

#include <type_traits>

template <typename T1, typename T2>
struct BiggerType {
using type = typename std::conditional<(sizeof(T1) > sizeof(T2)), T1, T2>::type;
};

template<typename T>
struct S {
using B = BiggerType<S, int>;

// This causes the instantiation of BiggerType,
// leading to calculation of sizeof(S) which is incomplete
void foo(const typename B::type& bt) {
}
};

int main() {
S<int> s;
}

Or in very compressed form,

template<typename T>
struct S {
// Same problem here
void foo(typename std::conditional<(sizeof(S) > sizeof(int)), S, int>::type&) {
}
};

error: invalid use of incomplete type (Maybe a definition issue)

You cannot. You can do such thing only for full specialization:

template <>
template <typename T>
static void RT<2, int>::internal_set_BC(int& d, T& t)
{//code
}

int is just example. You should write partial class specialization.

template<typename D>
class RT<2, D> : public BC<2, D>
{
// public functions set_BC.
private:
template <typename T>
static void internal_set_BC(D& d, T& t);
};

template <typename D>
template <typename T>
void RT<2, D>::internal_set_BC(D& d, T& t)
{//code
}

You can also write something like this, to specialize only internal_set_BC:

template<int n, typename D, typename Impl>
class RT_base : public BC<n, D>
{
public:
void set_BC(D& d, A& a)
{
Impl::internal_set_BC(d, a);
}
void set_BC(D& d, B& b)
{
Impl::internal_set_BC(d, b);
}
};

template <int n, typename D>
class RT: public RT_base<n, D, RT<n, D> >
{
friend class RT_base<n, D, RT<n, D> >;
template <typename T>
static void internal_set_BC(D& d, T& t);
};

template<typename D>
class RT<2, D> : public RT_base<2, D, RT<2, D> >
{
friend class RT_base<2, D, RT<2, D> >;
template <typename T>
static void internal_set_BC(D& d, T& t);
};

template <typename D>
template <typename T>
void RT<2, D>::internal_set_BC(D& d, T& t)
{//code
}

or more simple, without CRTP

template<int n, typename D>
class RT_Base : public BC<n, D>
{
protected:
template<typename T>
static void internal_set_BC(D& d, T& t);
};

template<typename D>
class RT_Base<2, D> : public BC<2, D>
{
protected:
template <typename T>
static void internal_set_BC(D& d, T& t);
};

template <typename D>
template <typename T>
void RT_Base<2, D>::internal_set_BC(D& d, T& t)
{//code
}

template<int n, typename D>
class RT : public RT_Base<n, D>
{
public:
void set_BC(D& d, A& a)
{
this->internal_set_BC(d, a);
}
void set_BC(D& d, B& b)
{
this->internal_set_BC(d, b);
}
};

invalid use of incomplete type

The reason is that when instantiating a class template, all its declarations (not the definitions) of its member functions are instantiated too. The class template is instantiated precisely when the full definition of a specialization is required. That is the case when it is used as a base class for example, as in your case.

So what happens is that A<B> is instantiated at

class B : public A<B>

at which point B is not a complete type yet (it is after the closing brace of the class definition). However, A<B>::action's declaration requires B to be complete, because it is crawling in the scope of it:

Subclass::mytype

What you need to do is delaying the instantiation to some point at which B is complete. One way of doing this is to modify the declaration of action to make it a member template.

template<typename T>
void action(T var) {
(static_cast<Subclass*>(this))->do_action(var);
}

It is still type-safe because if var is not of the right type, passing var to do_action will fail.



Related Topics



Leave a reply



Submit