Home > Blockchain >  Can you forward declare an explicit specialization of undeclared template class?
Can you forward declare an explicit specialization of undeclared template class?

Time:11-05

In the class I am currently writing, I consider it to be very important that most of its private member variables remain const. As such, I have opted to use an initialization object that is not fully declared in the header file:

// foo.h

template<typename T>
class Foo {
    const int *const memberVariable; // Important detail: pointer to a heap-allocated array
    const int otherMemberVariable;
    ...

    Foo(class FooInitializer &&initializer);

public:
    Foo(int constructorArgument, ...);
}

// foo.cpp

class FooInitializer {
    int *memberVariable; // Important detail: pointer to a heap-allocated array
    int otherMemberVariable;
    ...

    FooInitializer(int constructorArgument, ...) : memberVariable(constructorArgument, ...), ... {
        cuda_function(&memberVariable, &otherMemberVariable, ..., constructorArgument, ...);
        ...
    }
}

Foo::Foo(FooInitializer &&initializer) : memberVariable(std::move(initializer.memberVariable)), ... {}

Foo::Foo(int constructorArgument, ...) : Foo({constructorArgument, ...}) {}

However, this seems to break down if one of the constructor arguments or member variables must be of the type parameter type:

// foo.h

template<typename T>
class Foo {
    const int *const memberVariable; // Important detail: pointer to a heap-allocated array
    const int otherMemberVariable;
    ...

    Foo(class FooInitializer<T> &&initializer);

public:
    Foo(int constructorArgument, ...);
}

// foo.cpp

template<typename T>
class FooInitializer {
    int *memberVariable;
    int otherMemberVariable;
    ...

    FooInitializer(int constructorArgument, ...) : memberVariable(constructorArgument, ...), ... {
        cuda_function(&memberVariable, &otherMemberVariable, ..., constructorArgument, ...);
        ...
    }
}

template<typename T>
Foo<T>::Foo(FooInitializer<T> &&initializer) : memberVariable(std::move(initializer.memberVariable)), ... {}

template<typename T>
Foo<T>::Foo(int constructorArgument, ...) : Foo({constructorArgument, ...}) {}

I have tried some alternative syntaxes (such as Foo<T>::Foo(template<> FooInitializer<T> &&initializer) to no avail. I am opposed to temporary heap allocation, and I am trying to avoid introducing FooInitializer into the header's namespace due to essentially duplicate declarations of the member variables. I was considering the possibility of storing a const FooInitializer instance itself as the only member variable of Foo, but unfortunately that would make variables like memberVariable in the example above int *const, not const int *const. They cannot be C containers because they are allocated in device memory by CUDA functions.

Is there an alternative approach I have not considered?

CodePudding user response:

Foo(class FooInitializer<T> &&initializer);

Whereas you can declare (non-template) classes inside function declaration (int bar(struct S s);), I don't think you can for template classes.

I am trying to avoid introducing FooInitializer into the header's namespace due to essentially duplicate declarations of the member variables.

but you can still forward declare the class:

template <typename> class FooInitializer;

template<typename T>
class Foo
{
    // ...
    Foo(FooInitializer<T> &&initializer);
    // ...
};

Demo

  • Related