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 UnionBase
s 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
When Should You Use Constexpr Capability in C++11
Const VS Constexpr on Variables
How to Get Rid of 'Deprecated Conversion from String Constant to 'Char*'' Warnings in Gcc
Global Memory Management in C++ in Stack or Heap
Double Precision - Decimal Places
What Does It Mean to Have an Undefined Reference to a Static Member
When Should I Use Std::Thread::Detach
How to Convert a Lambda to an Std::Function Using Templates
How to Append Text to a Text File in C++
Explicit Specialization in Non-Namespace Scope
C/C++: Force Bit Field Order and Alignment
Benefits of Initialization Lists
How to Make a .Lib File When Have a .Dll File and a Header File