1

I'm trying to extend a template to add a function for a specific type.

This is what I have now:

template<typename T> class Item {
public:
    T value;
}

And I want to make it so Item<bool> has a operator bool(), like this:

template<> class Item<bool> : public Item<bool>{
public:
    explicit operator bool() const {
        return this->value; // error
    }
}

However, I get an error saying class 'Item<bool>' has no member 'value'.

What am I missing?

rev
  • 1,861
  • 17
  • 27
  • 1
    IMO, you cannot make a class inherit from itself ... Please consider renaming your `Item` template to something like `BaseItem`, and then make your `Item` class inherit from `BaseItem` – Unda Mar 31 '15 at 17:32
  • 1
    That's not the way you specialize a template class: `template<> class Item : public Item ...` – πάντα ῥεῖ Mar 31 '15 at 17:34
  • @πάνταῥεῖ so how should I do it? @Unda So there's no way to have `Item` have an extra function that `Item` don't have? – rev Mar 31 '15 at 17:35
  • 1
    Why not an an operator T for all types? – Neil Kirk Mar 31 '15 at 17:43
  • @NeilKirk because if I have e.g. `Item`, what's `if (item_string)` supposed to mean? – rev Mar 31 '15 at 17:44
  • 1
    @AcidShout This severely sounds like a XY problem for me. What do you want to achieve with this template class at all actually? – πάντα ῥεῖ Mar 31 '15 at 17:46
  • @πάνταῥεῖ in my case, every item represents a value set by the user, and in case it's a yes/no (bool), I want to be able to use `if (should_do_x)` instead of `if (should_do_x.value)`. (`should_do_x` is `Item`) – rev Mar 31 '15 at 17:51
  • @AcidShout I still don't get the requirement and use case. So what should the implementation actually do with a `Item x;` instance, whenever `if(x)` is called? – πάντα ῥεῖ Mar 31 '15 at 17:55
  • @πάνταῥεῖ that's exactly what I want to avoid. I don't want anybody calling `operator bool()` on anything that's not `Item`, because how can you determine the boolean value of a string? It doesn't make sense, that's why I want it only on `bool`s. – rev Mar 31 '15 at 17:59
  • I don't understand. You don't want `if (item_string)` to work, but you don't want to use `operator T` because `if (item_stirng)` won't work. – Neil Kirk Mar 31 '15 at 18:04
  • @AcidShout: Note that Neil is suggesting `operator T` for all types, NOT `operator bool`. For `Item` this would allow both `if(item_bool)` and `bool t=item_bool` to work. For `Item` this would allow only `string t = item_string` to work. – Mooing Duck Mar 31 '15 at 18:07
  • @NeilKirk sorry if I didn't explain myself properly. I want `Item x; if (x)` to work, but anything else, including `Item x; if (x)` to **not** work, as it's nonsense to try to evaluate strings as `bool`s. – rev Mar 31 '15 at 18:08
  • Correct. Therefore it wouldn't compile. – Neil Kirk Mar 31 '15 at 18:09
  • @AcidShout _"that's exactly what I want to avoid ..."_ I've updated my answer `std::static_assert()` is your friend to detect wrong usage at compile time. And there are sensible semantics I can imagine for that `operator bool()` being applied to a `std::string` BTW (think of e.g.`!value.empty()`). – πάντα ῥεῖ Mar 31 '15 at 18:10

3 Answers3

3

You can't extend template class declarations by introducing arbitrary member function declarations on type specializations.

You need to have that operator declaration appearing in the original class declaration:

template<typename T> class Item {
public:
    T value;
    operator bool() const {
         std::static_assert
            ( !std::is_same<T,bool>
            , "bool conversion is not available for this template parameter type."
            );
    }    
}; // <<< Note the semicolon BTW

and specialize it:

template<> 
Item<bool>::operator bool() const {
    return value;
}

The std::static_assert() will prevent any code from compiling, where you don't like an instantiation to make sense, besides of your own specializations.

πάντα ῥεῖ
  • 1
  • 13
  • 116
  • 190
  • Thanks, this did it. However, why can't I extend templated classes? As far as I know, templated stuff is evaluated at compile time, and for every type there's a new class generated with that specific type. Therefore, I should be able to tell the compiler to add one more function to a specific type. Isn't that right? – rev Mar 31 '15 at 17:57
  • 2
    @AcidShout You can actually extend derived templated classes using techniques like the CRTP (by means of mixin template parameters). Here are some leads [**"Possibility to mix composite pattern and curiously recurring template pattern"**](http://stackoverflow.com/questions/13867901/possibility-to-mix-composite-pattern-and-curiously-recurring-template-pattern/13868031#13868031), [**"Access “this” pointer of concrete class from interface"**](http://stackoverflow.com/questions/29085834/access-this-pointer-of-concrete-class-from-interface/29086484#29086484). – πάντα ῥεῖ Mar 31 '15 at 18:03
  • Should it still be operator T in the first case? – Neil Kirk Mar 31 '15 at 18:12
  • @NeilKirk You're right, I've changed that mistakenly. – πάντα ῥεῖ Mar 31 '15 at 18:16
2

The specialized class is not valid, it derives from itself. If you want to include some code in every specialization of a template class, you need to write this differently:

template<typename T> class ItemBase {
public:
    T value;
}

template<typename T> class Item {
    // generic implementation here
}

template<> class Item<bool> : public ItemBase<bool> {
public:
    explicit operator bool() const {
        return this->value;
    }
}
Krzysztof Kosiński
  • 4,225
  • 2
  • 18
  • 23
  • Though `operator bool() const;` is missing in the original class declaration :-(. – πάντα ῥεῖ Mar 31 '15 at 17:35
  • 1
    @πάνταῥεῖ that's just fine, I only want the `operator bool()` to appear on `Item` classes. – rev Mar 31 '15 at 17:36
  • You can also write `operator T() const` if you always want a conversion to `T`. – Krzysztof Kosiński Mar 31 '15 at 17:38
  • @KrzysztofKosiński no, I just want the `bool` conversion. My `Item` classes are storing values, and I want to be able to do `if (bool_object)` instead of `if (bool_object.value)`. – rev Mar 31 '15 at 17:39
  • @AcidShout: Do you want `string t = string_object;` to compile? Seems like it would be nice. You do that by adding `operator const T&() const` – Mooing Duck Mar 31 '15 at 18:09
0

You can't have a class inherit from itself. You might be trying to simulate the openness of classes that you are used to from other languages, e.g,. Python. However, C++ classes are not open - you cannot add to their implementation after defining them. With template classes, this means explicitly specializing the definition for your particular case. Yes, this does require code repetition if you do not design your class hierarchy correctly.

template<> class Item<bool>
{
public:
    bool value;
    explicit operator bool() const {
        return this->value; // error
    }
}
Pradhan
  • 16,391
  • 3
  • 44
  • 59
  • What do you mean 'correctly'? How would I do this 'correctly'? – rev Mar 31 '15 at 17:36
  • @AcidShout You should separate out functionality and move as much of the generic content to a templated base class, say `ItemGeneric` and restrict the specialization-specific code to explicit specializations of `ItemSpecific` which inherits from `ItemGeneric`. – Pradhan Mar 31 '15 at 17:38
  • It is all generic content for every `Item` object, and I'm doing exactly that: I've separated everything into `Item`, but I want `Item`s to have `explicit operator bool()` (specialization). Am I missing / misunderstanding something or there's simply no way to do it? – rev Mar 31 '15 at 17:42