Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > C++ > Overloaded function dilemma

Reply
Thread Tools

Overloaded function dilemma

 
 
Juha Nieminen
Guest
Posts: n/a
 
      10-16-2012
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?

 
Reply With Quote
 
 
 
 
Werner
Guest
Posts: n/a
 
      10-16-2012
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;
}
 
Reply With Quote
 
 
 
 
Victor Bazarov
Guest
Posts: n/a
 
      10-16-2012
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
 
Reply With Quote
 
Rui Maciel
Guest
Posts: n/a
 
      10-16-2012
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:stream & operator << (std:stream &os, Foo const &);
};


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


int main(void)
{
using namespace std;

Foo a( Foo:aram().optionA(1).optionB(2.0) );
Foo b( Foo:aram().optionB(3.0) );
Foo c( Foo:aram().optionA(5) );
Foo d( Foo:aram().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:aram class, which won't clash with any of Foo's
constructors.


Hope this helps,
Rui Maciel
 
Reply With Quote
 
Werner
Guest
Posts: n/a
 
      10-16-2012
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
 
Reply With Quote
 
Rui Maciel
Guest
Posts: n/a
 
      10-16-2012
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
 
Reply With Quote
 
Luca Risolia
Guest
Posts: n/a
 
      10-16-2012
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?

 
Reply With Quote
 
Juha Nieminen
Guest
Posts: n/a
 
      10-17-2012
Juha Nieminen <(E-Mail Removed)> 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.
 
Reply With Quote
 
Marc
Guest
Posts: n/a
 
      10-20-2012
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.
 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
Dilemma of const-ifying a function parameter hzmonte@hotmail.com C Programming 16 09-19-2006 09:18 PM
Passing a function pointer as an argument to an overloaded >> operator. glen stark C++ 3 09-30-2003 08:25 AM
why does my complier complain there is an overloaded function? Roy Yao C++ 4 08-21-2003 09:35 AM
operator= - code in overloaded function doesn't get called Tobias Langner C++ 2 07-31-2003 09:22 AM
Why can't '='(Assignment) operator be overloaded as friend function ? Nitin Bhardwaj C++ 8 07-14-2003 03:50 PM



Advertisments