Overloaded function dilemma

Discussion in 'C++' started by Juha Nieminen, Oct 16, 2012.

  1. For a series of classes I'm making it would be nice if they had constructors
    that accept:

    - an interator range,
    - an initializer list, and
    - a variable amount of arguments (using a variadic template)

    The first two are trivial, but the third one clashes badly with the first
    one. The third constructor is not absolutely mandatory, but it would be a
    nice-to-have feature. However, I must admit that regardless of my C++
    experience, I don't know if it could be even theoretically possible to
    have both the first and the third constructors at the same time.

    The problem is that the parameter types can be anything (or, more precisely,
    this is a templated class whose template type can be anything, and the
    variadic constructor would take parameters of that type). The parameters
    to the variadic constructor can very well be pointers.

    Therefore I don't see any way of distinguishing between the first and the
    third constructor: If you give the constructor two pointers, it matches
    both constructor overloads.

    Any ideas if this could even theoretically be possible?
    Juha Nieminen, Oct 16, 2012
    #1
    1. Advertising

  2. Juha Nieminen

    Werner Guest

    On Tuesday, October 16, 2012 9:16:38 AM UTC+2, Juha Nieminen wrote:
    > For a series of classes I'm making it would be nice if they had constructors
    >
    > that accept:
    >
    >
    >
    > - an interator range,
    >
    > - an initializer list, and
    >
    > - a variable amount of arguments (using a variadic template)
    >
    >
    >
    > The first two are trivial, but the third one clashes badly with the first
    >
    > one. The third constructor is not absolutely mandatory, but it would be a
    >
    > nice-to-have feature. However, I must admit that regardless of my C++
    >
    > experience, I don't know if it could be even theoretically possible to
    >
    > have both the first and the third constructors at the same time.
    >
    >
    >
    > The problem is that the parameter types can be anything (or, more precisely,
    >
    > this is a templated class whose template type can be anything, and the
    >
    > variadic constructor would take parameters of that type). The parameters
    >
    > to the variadic constructor can very well be pointers.
    >
    >
    >
    > Therefore I don't see any way of distinguishing between the first and the
    >
    > third constructor: If you give the constructor two pointers, it matches
    >
    > both constructor overloads.
    >
    >
    >
    > Any ideas if this could even theoretically be possible?


    This one seems a possibility:

    #include <iostream>
    #include <tuple>


    struct VariadicX
    {
    VariadicX( char* begin, char* end )
    {
    std::cout << "1 called" << std::endl;
    }

    VariadicX( std::initializer_list<char> )
    {
    std::cout << "2 called" << std::endl;
    }

    template <class ... Types>
    VariadicX( std::tuple<Types...>&& t )
    {
    std::cout << "3 && called" << std::endl;
    }

    };

    int main()
    {
    char array[] = { 'H', 'a', 'l', 'l', 'o' };

    VariadicX( array, array+sizeof(array) );
    VariadicX( { 'H', 'a', 'l', 'l', 'o' } );
    char *x = 0, *y = 0;
    VariadicX( std::make_tuple( x, 10 ) );
    VariadicX( std::make_tuple( x, y ) );
    return 0;
    }
    Werner, Oct 16, 2012
    #2
    1. Advertising

  3. On 10/16/2012 3:16 AM, Juha Nieminen wrote:
    > For a series of classes I'm making it would be nice if they had constructors
    > that accept:
    >
    > - an interator range,
    > - an initializer list, and
    > - a variable amount of arguments (using a variadic template)
    >
    > The first two are trivial, but the third one clashes badly with the first
    > one. The third constructor is not absolutely mandatory, but it would be a
    > nice-to-have feature. However, I must admit that regardless of my C++
    > experience, I don't know if it could be even theoretically possible to
    > have both the first and the third constructors at the same time.
    >
    > The problem is that the parameter types can be anything (or, more precisely,
    > this is a templated class whose template type can be anything, and the
    > variadic constructor would take parameters of that type). The parameters
    > to the variadic constructor can very well be pointers.
    >
    > Therefore I don't see any way of distinguishing between the first and the
    > third constructor: If you give the constructor two pointers, it matches
    > both constructor overloads.
    >
    > Any ideas if this could even theoretically be possible?


    I don't have an answer on the theoretical possibility, sorry. I am
    however thinking that you can often overcome some language limitations
    imposed on constructors by using named functions (static members that
    return an object). Similar to

    class Foo {
    public:
    template<class It> Foo(It i1, It i2); // pair of iterators
    // instead of another c-tor - a named "maker" function
    static Foo make_from_many( ... );
    };

    ...
    Foo foo(Foo::make_from_many( <whatever> ));

    I know it may not always be desirable, but it's clear and often actually
    solves the ambiguity problem since you can distinguish between the
    construction methods yourself instead of relying on the compiler.

    V
    --
    I do not respond to top-posted replies, please don't ask
    Victor Bazarov, Oct 16, 2012
    #3
  4. Juha Nieminen

    Rui Maciel Guest

    Juha Nieminen wrote:

    > For a series of classes I'm making it would be nice if they had
    > constructors that accept:
    >
    > - an interator range,
    > - an initializer list, and
    > - a variable amount of arguments (using a variadic template)
    >
    > The first two are trivial, but the third one clashes badly with the first
    > one. The third constructor is not absolutely mandatory, but it would be a
    > nice-to-have feature. However, I must admit that regardless of my C++
    > experience, I don't know if it could be even theoretically possible to
    > have both the first and the third constructors at the same time.
    >
    > The problem is that the parameter types can be anything (or, more
    > precisely, this is a templated class whose template type can be anything,
    > and the variadic constructor would take parameters of that type). The
    > parameters to the variadic constructor can very well be pointers.
    >
    > Therefore I don't see any way of distinguishing between the first and the
    > third constructor: If you give the constructor two pointers, it matches
    > both constructor overloads.
    >
    > Any ideas if this could even theoretically be possible?


    It appears that your problem is that you are trying to implement a design
    which inevitably will introduce a series ambiguity problems. Once you
    abandon the variadic template idea, you will solve your problem.

    If you are looking for clever ways to pass a a long list of arguments
    through a constructor, there are far better ways to pull this off, which
    don't require that you lose time writing an endless list of constructors for
    each object. As a suggestion, consider the following idea:

    - On your main classes (i.e., the ones which you intended to add those
    variadic templates), you only define three types of constructor: one taking
    an iterator range, one taking an initializer list, and one taking an object
    of a class defined specifically to pass parameters.
    - You implement each parameter-passing class as a named parameter idiom.


    Here's an example:

    <code>
    #include <iostream>


    // the main class
    class Foo
    {
    private:
    int m_a;
    float m_b;

    public:
    // parameter class, implementing a named parameter idiom
    struct Param
    {
    int a;
    float b;

    Param & optionA(int m_a) { a = m_a; return *this; }
    Param & optionB(float m_b) { b = m_b; return *this; }
    };

    public:
    Foo(Param const &params)
    {
    member1(params.a);
    member2(params.b);
    }

    void member1(int a)
    {
    m_a = a;
    }

    void member2(int b)
    {
    m_b = b;
    }

    friend std::eek:stream & operator << (std::eek:stream &os, Foo const &);
    };


    std::eek:stream & operator << (std::eek:stream &os, Foo const &foo)
    {
    return os << "{ a: " << foo.m_a << ", " << foo.m_b << "}";
    }


    int main(void)
    {
    using namespace std;

    Foo a( Foo::param().optionA(1).optionB(2.0) );
    Foo b( Foo::param().optionB(3.0) );
    Foo c( Foo::param().optionA(5) );
    Foo d( Foo::param().optionB(9.0).optionA(5) );

    cout << a << endl;
    cout << b << endl;
    cout << c << endl;
    cout << d << endl;

    return 0;
    }
    </code>


    If you still wish to use a variadic template constructor, you can pull this
    off on the Foo::param class, which won't clash with any of Foo's
    constructors.


    Hope this helps,
    Rui Maciel
    Rui Maciel, Oct 16, 2012
    #4
  5. Juha Nieminen

    Werner Guest

    On Tuesday, October 16, 2012 4:04:42 PM UTC+2, Rui Maciel wrote:

    > If you are looking for clever ways to pass a a long list of arguments
    >
    > through a constructor, there are far better ways to pull this off, which
    >
    > don't require that you lose time writing an endless list of constructors for
    >
    > each object. As a suggestion, consider the following idea:
    >
    >
    >
    > - On your main classes (i.e., the ones which you intended to add those
    >
    > variadic templates), you only define three types of constructor: one taking
    >
    > an iterator range, one taking an initializer list, and one taking an object
    >
    > of a class defined specifically to pass parameters.


    [snip]

    Having an object for specifically passing parameters implies
    that for handling new parameter types, the object
    interface requires modification (except when that object
    is something like a tuple that takes arbitrary amount of
    arguments/type).

    If the class should really be able to handle an arbitrary
    number of arguments of varying types, what better
    object than tuple in combination with variadic templates
    (or using a static named function is also a good idea Imho)?

    Kind regards,

    Werner
    Werner, Oct 16, 2012
    #5
  6. Juha Nieminen

    Rui Maciel Guest

    Werner wrote:

    > Having an object for specifically passing parameters implies
    > that for handling new parameter types, the object
    > interface requires modification (except when that object
    > is something like a tuple that takes arbitrary amount of
    > arguments/type).


    I'm not sure I understood what you meant by that. Could you please provide
    an example where implementing support for a new parameter doesn't require an
    interface to be modified?


    > If the class should really be able to handle an arbitrary
    > number of arguments of varying types, what better
    > object than tuple in combination with variadic templates
    > (or using a static named function is also a good idea Imho)?


    A tupple is actually a poor alternative, as it is nothing more than an ad-
    hoc definition of an aggregate type, which is essentially what a parameter
    class is, that introduces problems regarding ambiguity and lack of
    expressiveness.


    Rui Maciel
    Rui Maciel, Oct 16, 2012
    #6
  7. Juha Nieminen

    Luca Risolia Guest

    On 16/10/2012 09:16, Juha Nieminen wrote:
    > For a series of classes I'm making it would be nice if they had constructors
    > that accept:
    >
    > - an interator range,
    > - an initializer list, and
    > - a variable amount of arguments (using a variadic template)
    >
    > The first two are trivial, but the third one clashes badly with the first
    > one. The third constructor is not absolutely mandatory, but it would be a
    > nice-to-have feature. However, I must admit that regardless of my C++
    > experience, I don't know if it could be even theoretically possible to
    > have both the first and the third constructors at the same time.
    >
    > The problem is that the parameter types can be anything (or, more precisely,
    > this is a templated class whose template type can be anything, and the
    > variadic constructor would take parameters of that type). The parameters
    > to the variadic constructor can very well be pointers.
    >
    > Therefore I don't see any way of distinguishing between the first and the
    > third constructor: If you give the constructor two pointers, it matches
    > both constructor overloads.
    >
    > Any ideas if this could even theoretically be possible?


    Can you show us the code giving you the problems you described?
    Luca Risolia, Oct 16, 2012
    #7
  8. Juha Nieminen <> wrote:
    > For a series of classes I'm making it would be nice if they had constructors
    > that accept:
    >
    > - an interator range,
    > - an initializer list, and
    > - a variable amount of arguments (using a variadic template)


    From a more hypothetical point, in theory it could be possible to
    distinguish between an iterator range and a variable number of arguments
    because in the latter case all the arguments have to be compatible with
    the type accepted by the class. In other words, if you have something
    like this:

    template<typename Value_t>
    class MyClass
    {
    public:
    // All parameters have to be compatible with Value_t:
    template<typename... Params>
    MyClass(Params&&...);

    // If two paramers are given and they are *not* compatible with
    // Value_t, but *b and *e are compatible with Value_t, then this
    // ought to be called:
    template<typename InputIterator>
    MyClass(InputIterator b, InputIterator e);
    };

    In principle if you give the constructor values of type Value_t (or anything
    that's compatible with it, such as an object of a class derived from
    Value_t, if Value_t is a pointer to an object), that's distinguishable
    from two iterators which are not themselves compatible with Value_t, but
    their dereferences are.

    The standard library container classes usually do some template magic to
    distinguish between integrals and iterator ranges. For example
    std::vector<int> has a constructor that takes an iterator range and
    another constructor that takes two integrals. If you call the constructor
    with to ints, for example, it will match the iterator range constructor
    (because it's a better match than the other constructor, which takes a
    size_t and an int). However, std::vector still manages to do the right
    thing, thanks to some template magic.

    I was thinking that perhaps, possibly, the same kind of template trickery
    could be used in this case.
    Juha Nieminen, Oct 17, 2012
    #8
  9. Juha Nieminen

    Marc Guest

    Juha Nieminen wrote:

    > For a series of classes I'm making it would be nice if they had constructors
    > that accept:
    >
    > - an interator range,
    > - an initializer list, and
    > - a variable amount of arguments (using a variadic template)
    >
    > The first two are trivial, but the third one clashes badly with the first
    > one. The third constructor is not absolutely mandatory, but it would be a
    > nice-to-have feature. However, I must admit that regardless of my C++
    > experience, I don't know if it could be even theoretically possible to
    > have both the first and the third constructors at the same time.


    Why, yes, sfinae lets you do that. You can for instance disable the last
    one when it has 2 arguments that are iterators, where being an iterator
    is detected on good platforms by looking at iterator_traits and on
    others by being a pointer or having the right typedefs
    (iterator_category, etc), and disable the first one when its arguments
    are not iterators. Or if the variadic template can't take anything but
    say types convertible to some other type, you can also use that.
    Marc, Oct 20, 2012
    #9
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Chris
    Replies:
    0
    Views:
    404
    Chris
    Nov 10, 2003
  2. Kevin Spencer

    Events Dilemma

    Kevin Spencer, Oct 25, 2004, in forum: ASP .Net
    Replies:
    1
    Views:
    349
    Bishop
    Oct 25, 2004
  3. =?Utf-8?B?RGVtZXRyaQ==?=

    Web Service Dilemma

    =?Utf-8?B?RGVtZXRyaQ==?=, Nov 29, 2004, in forum: ASP .Net
    Replies:
    0
    Views:
    296
    =?Utf-8?B?RGVtZXRyaQ==?=
    Nov 29, 2004
  4. Don Parker
    Replies:
    1
    Views:
    349
    Eliyahu Goldin
    Jan 20, 2005
  5. Replies:
    16
    Views:
    466
    Michal Nazarewicz
    Sep 19, 2006
Loading...

Share This Page