Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Unable to declare a template variable without defining it

I am wanting to forward declare variable templates in a header file, and then have the actual instantiations in a separate compilation unit.

I was led to believe that C++14 variable templates operated very much like static class variables do. This is unfortunately seeming not to be quite the case, and it is preventing me from forward declaring my variable templates.

template <typename T> struct Variable {
    static int variable;
};

template <typename T> 
extern int variable;

int main() {
    (void) Variable<char>::variable;
    // (void) variable<char>;                   // <-- line 10
}

template <> int Variable<char>::variable = 42;
template <> int variable<char> = 23;

The code sample above compiles and runs as-is under GCC. But uncommenting line 10 gives a compile-time error:

specialization of 'variable<char>' after instantiation
    template <> int variable<char> = 23;
                     ^
like image 437
Tom Swirly Avatar asked Jan 24 '16 00:01

Tom Swirly


People also ask

Which Cannot be declared as a template?

Q. Which of the following cannot be declared as template ? Correct Answer : OPTION D, Macros. Macros are implemented in a preprocessor and cannot be implemented as a template.

How do I add a variable to a template?

Choose Template > New Variable from the editor toolbar (or choose an existing variable to add it to the page) Enter a name for the variable. Press Enter (by default this will create a single-line text input field)

Which keyword is used to set a variable in the template?

In the template, you use the hash symbol, # , to declare a template variable. The following template variable, #phone , declares a phone variable with the <input> element as its value.

What is a variable template in C++?

A variable template defines a family of variable (when declared at namespace scope) or a family of static data members (when defined at class scope).


1 Answers

I think you're on the right track.

The trick is this: In any one translation unit, don't instantiate the template prior to your specialization.

For example:

// test.h
#ifndef TEST_H
#define TEST_H

template <typename T> 
extern int variable;

template <> extern int variable<char>;
template <> extern int variable<int>;

#endif // TEST_H

Then:

// test2.cpp
#include "test.h"

template <> int variable<char> = 23;
template <> int variable<int> = 24;

And finally:

// test.cpp
#include "test.h"
#include <iostream>

int
main()
{
    std::cout << variable<char> << '\n';
    std::cout << variable<int> << '\n';
}

For me this outputs:

23
24

Update

T.C. points out in the comments below that the specializations need to be declared before first use, so I've updated "test.h" above to do that.

Update 2

There seems to be some implementation divergence. clang appears to handle this fine:

template <typename T> 
extern int variable;

template <> extern int variable<char>;
template <> extern int variable<int>;

#include <iostream>

int
main()
{
    std::cout << variable<char> << '\n';
    std::cout << variable<int> << '\n';
}

template <> int variable<char> = 23;
template <> int variable<int> = 24;

http://melpon.org/wandbox/permlink/DGYKvvoPbmRIHaFi

However gcc gives an error:

prog.cc:4:13: error: explicit template specialization cannot have a storage class
 template <> extern int variable<char>;
             ^~~~~~

prog.cc:5:13: error: explicit template specialization cannot have a storage class
 template <> extern int variable<int>;
             ^~~~~~

I've searched the standard and the Core Issues list, and I can't find anything to indicate one compiler or the other is correct. If someone does see such evidence, I'm happy to include it in this answer.

like image 57
Howard Hinnant Avatar answered Oct 17 '22 09:10

Howard Hinnant