By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
454,385 Members | 1,737 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 454,385 IT Pros & Developers. It's quick & easy.

conversion constructor

P: n/a
hi,

the following does not work. I do not understand why, since it works
if I replace line marked by (1) with the line below ((2)). Compiling
with gcc4.0 results in "error: conversion from 'Two<int>' to non-scalar
type 'One<int>' requested". Has somebody an explanation for me?
template <typename T>
struct Convert
{
typedef T Type;
};

template <typename T>
class One
{
public:
One() {}

template <typename I>
One(const typename Convert<I>::Type &rhs) {} // (1)
// One(const I &rhs) {} // (2)
};

template <typename S>
class Two
{
};

int
main()
{
One<int> y = Two<int>();
}
If I replace the constructor call in main() by an explicit call, it
works again with both versions. I know the difference of the two calls(
think so), but I cannot explain the different result.

regards,
Alex
Oct 26 '05 #1
Share this Question
Share on Google+
15 Replies


P: n/a
Alexander Stippler wrote:
hi,

the following does not work. I do not understand why, since it works
if I replace line marked by (1) with the line below ((2)). Compiling
with gcc4.0 results in "error: conversion from 'Two<int>' to non-scalar
type 'One<int>' requested". Has somebody an explanation for me?
template <typename T>
struct Convert
{
typedef T Type;
};

template <typename T>
class One
{
public:
One() {}

template <typename I>
One(const typename Convert<I>::Type &rhs) {} // (1)
// One(const I &rhs) {} // (2)
};

template <typename S>
class Two
{
};

int
main()
{
One<int> y = Two<int>();
Try:

One<int> y( Two<int>() );
}
If I replace the constructor call in main() by an explicit call, it
works again with both versions. I know the difference of the two calls(
think so), but I cannot explain the different result.

regards,
Alex


Cheers! --M

Oct 26 '05 #2

P: n/a
Alexander Stippler wrote:
the following does not work. I do not understand why, since it works
if I replace line marked by (1) with the line below ((2)). Compiling
with gcc4.0 results in "error: conversion from 'Two<int>' to non-scalar
type 'One<int>' requested". Has somebody an explanation for me?
template <typename T>
struct Convert
{
typedef T Type;
};

template <typename T>
class One
{
public:
One() {}

template <typename I>
One(const typename Convert<I>::Type &rhs) {} // (1)
// One(const I &rhs) {} // (2)
};

template <typename S>
class Two
{
};

int
main()
{
One<int> y = Two<int>();
So, let's try to see what happens here. If you use the (2), your 'I' is
anything, right (the c-tor is a template)? So, you declare 'One<T>' to
be constructible from any type through a const reference. It is also
constructible from another 'One<T>', through a copy constructor defined
by the compiler for you. The line above is, in fact the same as

typedef One<int> oi;

oi y( static_cast<oi>(Two<int>()) );

IOW, it constructs a temporary object of type Two<int>, then uses the user-
defined converstion to construct another temporary of One<int>, then copy-
constructs 'y' from the latter temporary. Then all temporaries are blown
away.

Now, what happens if you introduce Convert<I> there. You have the same
form

oi y( static_cast<oi>(Two<int>()) );

but now, how can 'static_cast' do its job? There is no conversion from
Two<int> to One<int>, only from Convert<???>::Type, given that ??? is
somehow figured out. For constructors, the template argument can _only_
be figured out from the type of the argument itself, not from a member of
some other template. What you're asking from the compiler is to figure out
what 'I' is if the argument to the constructor is 'Two<int>'. There is no
straight-forward, unambiguous, way to figure that out.
}
If I replace the constructor call in main() by an explicit call,
An explicit call to *what*? To some function?
it
works again with both versions. I know the difference of the two calls(
think so), but I cannot explain the different result.


The contexts for _deducing_ template arguments from a function call are much
more flexible than that for a constructor.

V
Oct 26 '05 #3

P: n/a

mlimber wrote:
Alexander Stippler wrote:

[snip]
int
main()
{
One<int> y = Two<int>();


Try:

One<int> y( Two<int>() );
}
If I replace the constructor call in main() by an explicit call, it
works again with both versions. I know the difference of the two calls(
think so), but I cannot explain the different result.


Oh, right. You knew that. Well, it's probably because the compiler
doesn't do a conversion lookup by instantiating another template. I'm
sure one of the language lawyers around here can cite the paragraph of
the standard for you.

Cheers! --M

Oct 26 '05 #4

P: n/a
In <hY*******************@newsread1.mlpsca01.us.to.ve rio.net> Victor
Bazarov wrote:
Alexander Stippler wrote:
the following does not work. I do not understand why, since it works
if I replace line marked by (1) with the line below ((2)). Compiling
with gcc4.0 results in "error: conversion from 'Two<int>' to non-
scalar type 'One<int>' requested". Has somebody an explanation for
me? template <typename T> struct Convert {
typedef T Type;
};

template <typename T>
class One
{
public:
One() {}

template <typename I>
One(const typename Convert<I>::Type &rhs) {} // (1)
// One(const I &rhs) {} // (2)
};

template <typename S>
class Two
{
};

int
main()
{
One<int> y = Two<int>();
So, let's try to see what happens here. If you use the (2), your 'I'
is anything, right (the c-tor is a template)? So, you declare
'One<T>' to be constructible from any type through a const reference.
It is also constructible from another 'One<T>', through a copy
constructor defined by the compiler for you. The line above is, in
fact the same as

typedef One<int> oi;

oi y( static_cast<oi>(Two<int>()) );

IOW, it constructs a temporary object of type Two<int>, then uses the
user- defined converstion to construct another temporary of One<int>,
then copy- constructs 'y' from the latter temporary. Then all
temporaries are blown away.

Now, what happens if you introduce Convert<I> there. You have the
same form

oi y( static_cast<oi>(Two<int>()) );

but now, how can 'static_cast' do its job? There is no conversion
from Two<int> to One<int>, only from Convert<???>::Type, given that ???
is somehow figured out. For constructors, the template argument can _
only_ be figured out from the type of the argument itself, not from a
member of some other template. What you're asking from the compiler
is to figure out what 'I' is if the argument to the constructor is
'Two<int>'. There is no straight-forward, unambiguous, way to figure
that out.
}
If I replace the constructor call in main() by an explicit call,


An explicit call to *what*? To some function?

with explicit call I meant
One<int> y(Two<int>());
instead of
One<int> y = Two<int>();
with regard to the keyword 'explicit'.
And I still do not understand why the first works, whereas the second
doesn't.
it works again with both versions. I know the difference of the two
calls( think so), but I cannot explain the different result.


The contexts for _deducing_ template arguments from a function call
are much more flexible than that for a constructor.

V


Alex
Oct 26 '05 #5

P: n/a
mlimber wrote:
[...]
Try:

One<int> y( Two<int>() );


Ahem... Isn't it a function declaration?
Oct 26 '05 #6

P: n/a
Alexander Stippler wrote:
[..]
with explicit call I meant
One<int> y(Two<int>());
instead of
One<int> y = Two<int>();
with regard to the keyword 'explicit'.
And I still do not understand why the first works, whereas the second
doesn't.


Try accessing any members of "y" now :-)

V
Oct 26 '05 #7

P: n/a
In <Te******************@newsread1.mlpsca01.us.to.ver io.net> Victor
Bazarov wrote:
Alexander Stippler wrote:
[..]
with explicit call I meant
One<int> y(Two<int>());
instead of
One<int> y = Two<int>();
with regard to the keyword 'explicit'.
And I still do not understand why the first works, whereas the second
doesn't.


Try accessing any members of "y" now :-)


Oh yes, I fell into this trap quite often :-((. So the solution I wanted
is not realizable.
What I originally wanted was some SFINAE construct for a constructor. Is
this somehow possible
without operating with a return value? I have the following:

template <typename T>
class A
{
public:
template <typename S>
A(const B<S> &rhs);
};

I have several instantiations of S and would like to allow all but one.
That's the reason for this
::Type construction which would then not be defined for this special type. Is there a way to realize
this concept?

Alex
Oct 26 '05 #8

P: n/a

Victor Bazarov wrote:
mlimber wrote:
[...]
Try:

One<int> y( Two<int>() );


Ahem... Isn't it a function declaration?


Oops! Good catch.

M

Oct 26 '05 #9

P: n/a
Alexander Stippler wrote:
What I originally wanted was some SFINAE construct for a constructor. Is
this somehow possible
without operating with a return value? I have the following:

template <typename T>
class A
{
public:
template <typename S>
A(const B<S> &rhs);
};

I have several instantiations of S and would like to allow all but one.
That's the reason for this
::Type construction which would then not be defined for this special type. Is there a way to realize
this concept?


Let me get this straight... You're trying to allow construction from all
B<S> except some specific B<SS>, right? SFINAE is a "selection" mechanism
that allows to "fall back" onto some generic solution instead of another
particular one. Is that what you want? What would be that generic
solution? Or do you, in fact, need to prohibit conversion of that B<SS>
into A<T>, for all T, but for a particular SS? And you need this in
compile-time, correct?

V
Oct 26 '05 #10

P: n/a
In <v6*******************@newsread1.mlpsca01.us.to.ve rio.net> Victor
Bazarov wrote:
Alexander Stippler wrote:
What I originally wanted was some SFINAE construct for a constructor.
Is this somehow possible without operating with a return value? I
have the following: template <typename T> class A {
public:
template <typename S>
A(const B<S> &rhs);
};

I have several instantiations of S and would like to allow all but
one. That's the reason for this
::Type construction which would then not be defined for this special
::type. Is there a way to realize
this concept?
Let me get this straight... You're trying to allow construction from
all B<S> except some specific B<SS>, right? SFINAE is a "selection"
mechanism that allows to "fall back" onto some generic solution
instead of another particular one. Is that what you want? What would
be that generic solution?

Or do you, in fact, need to prohibit
conversion of that B<SS> into A<T>, for all T, but for a particular SS?
And you need this in compile-time, correct?


Sorry for being unprecise. That's it, your second guess is absolutely
what I want. The compiler shall not consider the constructor above for
one specific SS. But how to realize?

Alex
Oct 26 '05 #11

P: n/a
Alexander Stippler wrote:
In <v6*******************@newsread1.mlpsca01.us.to.ve rio.net> Victor
Bazarov wrote:
Alexander Stippler wrote:
What I originally wanted was some SFINAE construct for a constructor.
Is this somehow possible without operating with a return value? I
have the following: template <typename T> class A {
public:
template <typename S>
A(const B<S> &rhs);
};

I have several instantiations of S and would like to allow all but
one. That's the reason for this
::Type construction which would then not be defined for this special
::type. Is there a way to realize
this concept?


Let me get this straight... You're trying to allow construction from
all B<S> except some specific B<SS>, right? SFINAE is a "selection"
mechanism that allows to "fall back" onto some generic solution
instead of another particular one. Is that what you want? What would
be that generic solution?


Or do you, in fact, need to prohibit
conversion of that B<SS> into A<T>, for all T, but for a particular SS?
And you need this in compile-time, correct?

Sorry for being unprecise. That's it, your second guess is absolutely
what I want. The compiler shall not consider the constructor above for
one specific SS. But how to realize?


Ok, let me restate the problem:
-------------------------------------------------
template<class T> class From {};
class Special {};
// template<> class From<Special> {}; // you don't need this, actually

template<class T> class To {
public:
template<class U> To(const From<U>&);
};

int main() {
From<int> good;
From<Special> bad;
To<int> to_int(good);
To<char> to_char(good);
To<int> to_int2(bad); // ******************** should not compile!
}
-------------------------------------------------
As is, without any special trick, the code above compiles (or at least
should compile with a compliant compiler), nothing to it.

Now, if we need to prohibit construction of 'To' from a particular From
instantiation we could define a non-template constructor (overloaded
constructor) from that type in the _private_ section of the 'To' template:
-------------
....
template<class T> class To {
To(const From<Special>&);
public:
template<class U> To(const From<U>&);
};
....
-------------
Having the overloaded constructor in the private section does not let
the 'to_int2' to be instantiated from 'bad', but only _outside_ of the
class template 'To' itself.

Is this something you can use or do you need a more generic solution?

Victor
Oct 26 '05 #12

P: n/a
In <ps*******************@newsread1.mlpsca01.us.to.ve rio.net> Victor
Bazarov wrote:
Alexander Stippler wrote:
In <v6*******************@newsread1.mlpsca01.us.to.ve rio.net> Victor
Bazarov wrote:
Alexander Stippler wrote:

What I originally wanted was some SFINAE construct for a constructor.
Is this somehow possible without operating with a return value? I
have the following: template <typename T> class A {
public:
template <typename S>
A(const B<S> &rhs);
};

I have several instantiations of S and would like to allow all but
one. That's the reason for this
::Type construction which would then not be defined for this special
::type. Is there a way to realize
this concept?

Let me get this straight... You're trying to allow construction from
all B<S> except some specific B<SS>, right? SFINAE is a "selection"
mechanism that allows to "fall back" onto some generic solution
instead of another particular one. Is that what you want? What
would be that generic solution?


Or do you, in fact, need to prohibit
conversion of that B<SS> into A<T>, for all T, but for a particular
SS? And you need this in compile-time, correct?

Sorry for being unprecise. That's it, your second guess is absolutely
what I want. The compiler shall not consider the constructor above
for one specific SS. But how to realize?


Ok, let me restate the problem:
-------------------------------------------------
template<class T> class From {};
class Special {};
// template<> class From<Special> {}; // you don't need this, actually

template<class T> class To {
public:
template<class U> To(const From<U>&);
};

int main() {
From<int> good;
From<Special> bad;
To<int> to_int(good);
To<char> to_char(good);
To<int> to_int2(bad); // ******************** should not compile!
}
-------------------------------------------------
As is, without any special trick, the code above compiles (or at least
should compile with a compliant compiler), nothing to it.

Now, if we need to prohibit construction of 'To' from a particular
From instantiation we could define a non-template constructor (
overloaded constructor) from that type in the _private_ section of the
'To' template: ------------- .... template<class T> class To { To(
const From<Special>&); public: template<class U> To(const From<U>&);
};
....
-------------
Having the overloaded constructor in the private section does not let
the 'to_int2' to be instantiated from 'bad', but only _outside_ of the
class template 'To' itself.

Is this something you can use or do you need a more generic solution?

Victor


Thanks for your effort. Trying to figure out if your solution works for
me, I realized I probably haven't completely understood my problem.
(Nevertheless your answers gave me new inspiration in another field :-))
So I post my original problem to you again hoping you can comprehend the
compiler behavior:

template <typename Impl>
class Vector
{
};

template <typename Ref>
class VectorView
: : public Vector<VectorView<Ref> >
{
public:
operator const Ref &() const {}
};

template <typename T>
class DenseVector
: : public Vector<DenseVector<T> >
{
public:
DenseVector() {}

template <typename Impl>
DenseVector(const Vector<Impl> &rhs) {}

VectorView<DenseVector<T> >
operator()(int from, int to) {}
};

int amin(const DenseVector<double> &x) { return 1; }
int amin(const DenseVector<float> &x) { return -1; }

int
main()
{
DenseVector<double> x;
int i = amin(x(1,3));
}

The way I would want it to work is that if a VectorView<DenseVector<T> >
object is used in a function where the signature expects a
DenseVector<T>
then it should be used converted to DenseVector<T>, but not allowed to
be
converted to DenseVector<OTHER_T>.
Please ask, if anything is not clear. The code above results in:

small.cc:36: error: call of overloaded 'amin(
VectorView<DenseVector<double> >)' is ambiguous
small.cc:29: note: candidates are: int amin(const DenseVector<double>&)
small.cc:30: note: int amin(const DenseVector<float>&)
Oct 26 '05 #13

P: n/a
Alexander Stippler wrote:
[..] Trying to figure out if your solution works for
me, I realized I probably haven't completely understood my problem.
(Nevertheless your answers gave me new inspiration in another field :-))
So I post my original problem to you again hoping you can comprehend the
compiler behavior:

template <typename Impl>
class Vector
{
};

template <typename Ref>
class VectorView
: : public Vector<VectorView<Ref> >
{
public:
operator const Ref &() const {}
};

template <typename T>
class DenseVector
: : public Vector<DenseVector<T> >
{
public:
DenseVector() {}

template <typename Impl>
DenseVector(const Vector<Impl> &rhs) {}
Why is this a template, then? Shouldn't it just be a straight-up
parameterized constructor? See my example below.
VectorView<DenseVector<T> >
operator()(int from, int to) {}
};

int amin(const DenseVector<double> &x) { return 1; }
int amin(const DenseVector<float> &x) { return -1; }

int
main()
{
DenseVector<double> x;
int i = amin(x(1,3));
}

The way I would want it to work is that if a VectorView<DenseVector<T> >
object is used in a function where the signature expects a
DenseVector<T>
then it should be used converted to DenseVector<T>, but not allowed to
be
converted to DenseVector<OTHER_T>.
Please ask, if anything is not clear. The code above results in:

small.cc:36: error: call of overloaded 'amin(
VectorView<DenseVector<double> >)' is ambiguous
small.cc:29: note: candidates are: int amin(const DenseVector<double>&)
small.cc:30: note: int amin(const DenseVector<float>&)


template<class Impl>
class Vector
{
};

template<class Ref>
class VectorView: public Vector<VectorView<Ref> >
{
Ref r;
public:
VectorView() : Vector<VectorView<Ref> >() {}
operator const Ref &() const { return r; }
};

template<class T>
class DenseVector: public Vector<DenseVector<T> >
{
public:
DenseVector() {}
DenseVector(const Vector<T> &rhs) {}

VectorView<DenseVector<T> > operator()(int from, int to)
{
return VectorView<DenseVector<T> >();
}
};

int amin(const DenseVector<double> &x) { return 1; }
int amin(const DenseVector<float> &x) { return -1; }

int main()
{
DenseVector<double> x;
return amin(x(1,3));
}
-----------------------------------------

V
Oct 26 '05 #14

P: n/a
Alexander Stippler wrote:
In <Te******************@newsread1.mlpsca01.us.to.ver io.net> Victor
Bazarov wrote:
Alexander Stippler wrote:
[..]
with explicit call I meant
One<int> y(Two<int>());
instead of
One<int> y = Two<int>();
with regard to the keyword 'explicit'.
And I still do not understand why the first works, whereas the second
doesn't.


Try accessing any members of "y" now :-)


Oh yes, I fell into this trap quite often :-((. So the solution I wanted
is not realizable.
What I originally wanted was some SFINAE construct for a constructor. Is
this somehow possible
without operating with a return value? I have the following:

template <typename T>
class A
{
public:
template <typename S>
A(const B<S> &rhs);
};

I have several instantiations of S and would like to allow all but one.
That's the reason for this
::Type construction which would then not be defined for this special type. Is there a way to realize
this concept?


Why not declare (but not define) a private constructor for the
disallowed type (SS in the following example):

class SS;

template <class T>
class A
{
public:
template <class S>
A( const B<S>& rhs);

private:
A (const B<SS>& rhs);
};

Since the compiler prefers non-template functions over template
functions when resolving an overload, the private constructor will be
the one selected when trying to convert a B<SS> to a class A object.

Greg

Oct 27 '05 #15

P: n/a
In <_p******************@newsread1.mlpsca01.us.to.ver io.net> Victor
Bazarov wrote:
Alexander Stippler wrote:
[..] Trying to figure out if your solution works for
me, I realized I probably haven't completely understood my problem.
(Nevertheless your answers gave me new inspiration in another field :-))
So I post my original problem to you again hoping you can comprehend
the compiler behavior: template <typename Impl> class Vector {
};

template <typename Ref>
class VectorView
: : public Vector<VectorView<Ref> >
{
public:
operator const Ref &() const {}
};

template <typename T>
class DenseVector
: : public Vector<DenseVector<T> >
{
public:
DenseVector() {}

template <typename Impl>
DenseVector(const Vector<Impl> &rhs) {}


Why is this a template, then? Shouldn't it just be a straight-up
parameterized constructor? See my example below.


because Impl is never T. It may be DenseVector<T>, but here the copy
constructor will be chosen. Impl can be instantiated by various types
of Vectors, e.g. VectorClosure<Op, Lhs, Rhs>, also derived from Vector.
For all other types of Impl the behavior is OK. But for VectorView
(representing some sub-vector) the VectorView object shall only be
converted back to the underlying vector type, but the compiler
considers the template constructor and thus finds ambiguities. Short:
All other vector types convertible by the template constructor.
VectorView<Ref> only convertibe to Ref. That's what I want. The code
was only the shortest way to present the problem. I have several Matrix
as well as Vector types.
VectorView<DenseVector<T> >
operator()(int from, int to) {}
};

int amin(const DenseVector<double> &x) { return 1; }
int amin(const DenseVector<float> &x) { return -1; }

int
main()
{
DenseVector<double> x;
int i = amin(x(1,3));
}

The way I would want it to work is that if a
VectorView<DenseVector<T> > object is used in a function where the
signature expects a DenseVector<T> then it should be used converted
to DenseVector<T>, but not allowed to be converted to
DenseVector<OTHER_T>. Please ask, if anything is not clear. The code
above results in: small.cc:36: error: call of overloaded 'amin(
VectorView<DenseVector<double> >)' is ambiguous small.cc:29: note:
candidates are: int amin(const DenseVector<double>&) small.cc:30:
note: int amin(const DenseVector<float>&)


template<class Impl>
class Vector
{
};

template<class Ref>
class VectorView: public Vector<VectorView<Ref> >
{
Ref r;
public:
VectorView() : Vector<VectorView<Ref> >() {}
operator const Ref &() const { return r; }
};

template<class T>
class DenseVector: public Vector<DenseVector<T> >
{
public:
DenseVector() {}
DenseVector(const Vector<T> &rhs) {}

VectorView<DenseVector<T> > operator()(int from, int to)
{
return VectorView<DenseVector<T> >();
} } ;

int amin(const DenseVector<double> &x) { return 1; }
int amin(const DenseVector<float> &x) { return -1; }

int main()
{
DenseVector<double> x;
return amin(x(1,3));
}
-----------------------------------------

V

Oct 27 '05 #16

This discussion thread is closed

Replies have been disabled for this discussion.