7

How should I initialize a static variable for a partial specialization?

template <bool A=true, bool B=false>
struct from {
    const static std::string value; 
};

// no specialization - works
template <bool A, bool B>
const std::string from<A, B>::value = "";

// partial specialization - does not compile -  
// Error: template argument list following class template name must list parameters in the order used in template parameter list
// Error: from<A,B>' : too few template arguments
template <bool B>
const std::string from<true, B>::value = "";

// full specialization - works
const std::string from<false, true>::value = "";

Why doesn't the partial work?

EDIT: I found a solution based on Partial template specialization for initialization of static data members of template classes

I need to repeat the declaration for the partial specialization before it allowed me to initialize the static variable:

template <bool B>
struct from<true, B> {
    const static std::string value; 
};

Again, the question is why?

Community
  • 1
  • 1
Candy Chiu
  • 6,579
  • 9
  • 48
  • 69
  • Which compiler? On [g++ 4.3.4](http://ideone.com/jM6sIb), the last one doesn't work either. – didierc Nov 15 '12 at 19:34
  • Don't you have to specialize the entire class template, too? I think only explicit (= full) specialization is allowed for members. – Kerrek SB Nov 15 '12 at 19:36

2 Answers2

4

Partial specialization of members (whether they're functions or static data) are not allowed without partial specialization of enclosing class template itself.

That is, you have to specialize the class template also. So the following should work:

//partial specialization of class template
template <bool B>
struct from<true, B> {
    const static std::string value; 
};

//now you can do this!    
template <bool B>
const std::string from<true, B>::value = ""

Also, this will not compile (have you tried compiling this?):

// full specialization - works (SORRY, IT WILL NOT WORK!)
const std::string from<false, true>::value = "";  //this should be an error

You've to write this:

// full specialization 
template<>   //<---- this is important!
const std::string from<false, true>::value = ""
Nawaz
  • 353,942
  • 115
  • 666
  • 851
  • Ok. My goal is to replace some if-the-else statement by the templates. I see that using static variables in this particular scenario is problematic. Would you recommend a way to fix this issue? I'd like select a string based on the template parameter values. – Candy Chiu Nov 15 '12 at 19:43
  • @CandyChiu: Why not use array/map of string instead? Or you could use member function in a class template which will returns different value based on the value of template arguments. – Nawaz Nov 15 '12 at 19:46
  • I want compile time selection. – Candy Chiu Nov 15 '12 at 19:49
  • @CandyChiu: Why? What would you do with `std::string` at compile-time? – Nawaz Nov 15 '12 at 19:50
  • the code i am trying to replace is four similar classes differ by a few strings. template seems like the good choice to combined them into 1. – Candy Chiu Nov 15 '12 at 19:56
  • @CandyChiu: But why do you need the selection at compile-time when you cannot process it? Also, `std::string` is not compile-time constant. They can be at most read-only. So you could just use some predefined map of strings. That should work just fine! – Nawaz Nov 15 '12 at 19:59
  • The selection is at compile time, because right now A=true,B=false is actually a class which inherits from some parent. I know the value of A and B at compile time. – Candy Chiu Nov 15 '12 at 20:06
  • by the way, const std::string from::value = ""; compiles in VS2010 withOUT the leading template <> – Candy Chiu Nov 16 '12 at 13:09
  • I'm sorry for too late comment but you forgot semicolons after `value` constant definitions. – Constructor Apr 04 '14 at 17:24
2

Here's a working full specialization of the template.

#include <string>
#include <iostream> 

template <bool A=true, bool B=false>
struct from {
  const static std::string value; 
};

// no specialization - works
template <bool A, bool B>
const std::string from<A, B>::value = "no specialization";

// full specialization, note the empty template parameter list
template <>
const std::string from<true, true>::value = "<true,true> specialization";


int main() {
   std::cout << from<false, false>::value << std::endl;
   std::cout << from<true, true>::value << std::endl;
}

You found the correct way of defining the partial.

The reason for your partial not working is that you need to declare the structure type before being able to provide an initialization for its static field. The partial specialization is a template in its own right, and deserves a definition.

The full specialization is actually a type instance of the initial template, and thus doesn't need to be defined separately.

didierc
  • 14,572
  • 3
  • 32
  • 52