Velocity Reviews

Velocity Reviews (http://www.velocityreviews.com/forums/index.php)
-   C++ (http://www.velocityreviews.com/forums/f39-c.html)
-   -   Overloaded function dilemma (http://www.velocityreviews.com/forums/t953429-overloaded-function-dilemma.html)

Juha Nieminen 10-16-2012 07:16 AM

Overloaded function dilemma
 
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?


Werner 10-16-2012 09:29 AM

Re: Overloaded function dilemma
 
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;
}

Victor Bazarov 10-16-2012 01:27 PM

Re: Overloaded function dilemma
 
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

Rui Maciel 10-16-2012 02:04 PM

Re: Overloaded function dilemma
 
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::ostream & operator << (std::ostream &os, Foo const &);
};


std::ostream & operator << (std::ostream &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

Werner 10-16-2012 03:35 PM

Re: Overloaded function dilemma
 
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

Rui Maciel 10-16-2012 04:23 PM

Re: Overloaded function dilemma
 
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

Luca Risolia 10-16-2012 05:47 PM

Re: Overloaded function dilemma
 
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?


Juha Nieminen 10-17-2012 06:29 AM

Re: Overloaded function dilemma
 
Juha Nieminen <nospam@thanks.invalid> 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.

Marc 10-20-2012 08:06 AM

Re: Overloaded function dilemma
 
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.


All times are GMT. The time now is 08:52 AM.

Powered by vBulletin®. Copyright ©2000 - 2014, vBulletin Solutions, Inc.
SEO by vBSEO ©2010, Crawlability, Inc.