4

I would like to make a class with several constructors of the same type. As this is not directly possible, is there a simple way to define readable "dummy" types such as the class could look like:

class Myclass
{
    MyClass(Orange, std::string & name, float size);
    MyClass(Apple, std::string & name, float size);
    MyClass(Banana, std::string & name, float size);
}

I could define Orange, Apple and Banana as struct typedefs, but is there a more convenient way?

Thanks

Zini
  • 909
  • 7
  • 15
galinette
  • 8,896
  • 2
  • 36
  • 87
  • 4
    It seems to me `MyClass` is a base class, and you want three subclasses. – jxh Apr 04 '14 at 20:56
  • Would a factory class be more appropriate? `MyClass.CreateBanana("Bananco", 10f);` – Matthew Apr 04 '14 at 20:57
  • @jxh : this is exactly what I'm trying to get rid of. With a large number of small subclasses (>30) this is a mess, it's not copyable & passable by value without a shared pointer/clone wrapper class mechanism, requires dynamic casting, etc... and in my particular case it will be much simpler like that. – galinette Apr 04 '14 at 21:19
  • @ matthew : Yes, I considered it. But it lacks the possibilities of initializer lists and hence const members. – galinette Apr 04 '14 at 21:21

4 Answers4

5

The standard library does this in various places actually, for example std::piecewise_construct_t. Their standard is to provide...

struct something_t {};

constexpr something_t something = something_t();
David
  • 27,652
  • 18
  • 89
  • 138
  • did you forget the typedefs? – galinette Apr 04 '14 at 21:06
  • I did not think it was possible to define an empty struct. Do I pass it by value or by pointer/reference? If by value, can the compiler completely optimize it out so that it's just here for strong typing at compile-time? – galinette Apr 04 '14 at 21:08
  • Hmm OK I was still thinking about C struct typedef requirement – galinette Apr 04 '14 at 21:09
  • 1
    @galinette By value, and yes it will be completely compiled out. And you can certainly define an empty struct. The purpose of `something` is so the user can pass that global into your constructor: `MyClass c(something, "name", 12.3f);` They actually don't really need to know about `something_t` – David Apr 04 '14 at 21:09
  • geeez I'm becoming a c++ guru (just kidding) – galinette Apr 04 '14 at 21:12
3

Yes you can tag dispatch to overload the constructor arbitrarily:

struct Orange{};
struct Apple{};
struct Banana{};

class MyClass
{
    MyClass(Orange, std::string & name, float size){}
    MyClass(Apple, std::string & name, float size){}
    MyClass(Banana, std::string & name, float size){}
};

int main()
{
    std::string name("Fred");   
    MyClass myObject(Orange(), name, 10.0f);

    return 0;
}
PeterSW
  • 4,921
  • 1
  • 24
  • 35
3

How about using a template parameter?

struct Orange {};
class MyClass
{
public:
    template<typename CT>
    MyClass(CT, std::string & name, float size);
};

template<>
MyClass::MyClass<Orange>(Orange, std::string & name, float size)
{
    // The orange case
}

Which could be used as:

int main()
{
    std::string name("Fred");
    MyClass myObject(Orange(), name, 12.0f);
    return 0;
}

In the above form it is just a more complex route to the tag dispatch approach.
The advantage comes in that you can add extra details into template parameter and make a generic constructor based on them:

struct Orange { static const int pips = 7; };
struct Banana { static const int pips = 1; };

class MyClass
{
    int pips;
public:
    enum ConstructorType {Orange, Apple, Banana};
    template<typename CT>
    MyClass(CT, std::string & name, float size);
};

template<typename CT>
MyClass::MyClass(CT, std::string & name, float size)
: pips(CT::pips)
{

}
PeterSW
  • 4,921
  • 1
  • 24
  • 35
  • I did not know it was possible to template a constructor without templating the class, that's interesting. Thanks! – galinette Apr 05 '14 at 10:47
1

You can use the Named constructor idiom. Basically, you create static methods with different names which return new objects.

Geier
  • 894
  • 7
  • 16
  • I know this one, the issue is you can't use initializer lists as in a constructor. This means, no const members, double initializations, etc... not ideal – galinette Apr 04 '14 at 21:03