简体   繁体   中英

Yet another class template specialisation (on a boolean parameter)

I am trying to specialise a very simple class templated on an integer, as follows.

#include <iostream>
#include <string>


constexpr bool is_even(int n) {
    if (n % 2 == 0)
        return true;
    else
        return false;
}


template<int N, bool b = is_even(N)>
class Number {
public:
  Number() {}
  void say() { std::cout << "I'm " + type << std::endl; }; 
private:
  std::string type;
};


// This seems to be the most natural way of doing the specialisation
template<int N>
Number<N, false>::Number() : type ("odd") {}


// Alternative specialisation I hoped would have worked
template<int N> class Number<N, true> {
public:
    Number() : type ("even") {}
};


int main() {
    Number<2> a;
    Number<3> b;

    a.say();
    b.say();
}

However, it seems I am doing something wrong in both partial specialisations. The compiler seems to be hinting I am declaring the false constructor inside the true constructor:

a.cc:26:26: error: invalid use of incomplete type ‘class Number<N, false>’
   26 | Number<N, false>::Number() : type ("odd") {}
      |                          ^
a.cc:15:7: note: declaration of ‘class Number<N, false>’
   15 | class Number {
      |       ^~~~~~
a.cc: In constructor ‘Number<N, true>::Number()’:
a.cc:32:13: error: class ‘Number<N, true>’ does not have any field named ‘type’
   32 |  Number() : type ("even") {}
      |             ^~~~
a.cc: In function ‘int main()’:
a.cc:40:4: error: ‘class Number<2>’ has no member named ‘say’
   40 |  a.say();

so maybe there's a syntax error somewhere? If so, the compiler is not helping in telling me where.

It seems as if the specialisation of my class does not know that we declared the string "type" as a private field in the general class.

Also, I noted that the compiler is not happy with a.say() , but seems to be fine with b.say() .

For this attempt:

template<int N>
Number<N, false>::Number() : type ("odd") {}

You cannot define a member function of a partially-specialized class if you have not partially specialized the whole class, ie, declared the partial specialization before. See, eg, Partial specialization of template class copy constructor .

For this attempt:

template<int N> class Number<N, true> {
public:
    Number() : type ("even") {}
};

You did a partial specialization of the whole class, which is perfectly valid, but doing so, you got a completely different class from the non-specialized version, thus the type member does not exists in this one.

What you would need is something like:

template<int N>
class Number<N, false> {
public:
  Number() : type("odd") {}

  // You need to re-declare everything...
  void say() { std::cout << "I'm " + type << std::endl; }; 
private:
  std::string type;
};

...in which cases you'd probably want to rethink your whole design, because re-declaring the whole class for both case is probably not what you want.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM