 |
C++Talk.NET C++ language newsgroups
|
| View previous topic :: View next topic |
| Author |
Message |
Jaap Suter Guest
|
Posted: Wed Sep 22, 2004 10:00 am Post subject: enable_if like behaviour for conversion operators |
|
|
Hi,
consider the following code:
template<class T, int N>
struct vector
{
T m[N];
};
Now, I'd like to make the following compile:
vector<float, 1> scalar;
scalar[0] = 1.0f;
float f = scalar;
But this should not compile:
vector<float, 2> v;
float f = v;
Does anybody have any ideas on how this can be achieved?. I tried
coming up with ways to use enable_if, but it seem useless for
conversion operators.
I have already managed to use enable_if to make the following work:
vector<float, 2> v(2.0f, 2.0f); // compiles
vector<float, 2> w(2.0f); // doesn't compile
vector<float, 1> x(2.0f); // compiles
vector<float, 1> y(2.0f, 2.0f); // doesn't compile
But the reverse (making 1-dimensional vectors behave as built-in
scalars) seems harder.
Mmm, come to think of it, perhaps I can selectively derive from a base
class based on the 'N' parameter. The 1-dimensional base class injects
the proper operator overload, and the others don't. Seems like a nasty
approach (the member array needs to move to the base class then)
though.
Thoughts are welcome.
Thanks,
Jaap Suter
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Rob Williscroft Guest
|
Posted: Wed Sep 22, 2004 6:40 pm Post subject: Re: enable_if like behaviour for conversion operators |
|
|
Jaap Suter wrote in news:5e7a0d2.0409212040.552c2d1 (AT) posting (DOT) google.com in
comp.lang.c++.moderated:
| Quote: | Hi,
consider the following code:
template<class T, int N
struct vector
{
T m[N];
};
Now, I'd like to make the following compile:
vector
scalar[0] = 1.0f;
float f = scalar;
But this should not compile:
vector<float, 2> v;
float f = v;
Does anybody have any ideas on how this can be achieved?. I tried
coming up with ways to use enable_if, but it seem useless for
conversion operators.
|
Yep, it disables Template Argument Deduction, so the compiler will
never even try to instantiate it.
However enable_if is only realy useful if there is some other function
(conversion path in this case) that might succed, but you seem to
want failure, so I'm not sure you should be even trying to use it,
it might clean up the error messages a bit, but that is all.
| Quote: |
I have already managed to use enable_if to make the following work:
vector<float, 2> v(2.0f, 2.0f); // compiles
vector<float, 2> w(2.0f); // doesn't compile
vector<float, 1> x(2.0f); // compiles
vector<float, 1> y(2.0f, 2.0f); // doesn't compile
But the reverse (making 1-dimensional vectors behave as built-in
scalars) seems harder.
Mmm, come to think of it, perhaps I can selectively derive from a base
class based on the 'N' parameter. The 1-dimensional base class injects
the proper operator overload, and the others don't. Seems like a nasty
approach (the member array needs to move to the base class then)
though.
|
If all you want is for the conversion to fail (and I can't think
what else you might want) then:
template<class T, int N> struct scalar_conversion_only;
template<class T>
struct scalar_conversion_only< T, 1 >
{
static T &apply( T *p ) { return *p; }
};
template<class T, int N>
struct vector
{
T m[N];
operator T ()
{
return scalar_conversion_only< T, N >::apply( m );
}
};
int main()
{
vector<float, 1> scalar;
scalar.m[0] = 1.0f;
float f = scalar;
vector<float, 2> v2;
float f2 = v2;
}
CbuilderX:
test.cpp:21: error incomplete type is not allowed detected during
instantiation of "vector<T, N>::operator T() [with T=float, N=2]"
at line 33
MSVC 7.1 (first line only:
test.cpp(1 : error C2027: use of undefined type
'scalar_conversion_only<T,N>'
with
[
T=float,
N=2
]
g++ 3.4:
test.cpp: In member function `vector<T, N>::operator T()
[with T = float, int N = 2]':
test.cpp:31: instantiated from here
test.cpp:18: error: incomplete type
`scalar_conversion_only<float, 2>' used in nested name specifier
Rob.
--
http://www.victim-prime.dsl.pipex.com/
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Hyman Rosen Guest
|
Posted: Wed Sep 22, 2004 6:48 pm Post subject: Re: enable_if like behaviour for conversion operators |
|
|
Jaap Suter wrote:
| Quote: | Now, I'd like to make the following compile:
vector<float, 1> scalar;
scalar[0] = 1.0f;
float f = scalar;
But this should not compile:
vector<float, 2> v;
float f = v;
|
Just partially specialize the N = 1 case.
template<class T, int N>
struct vector
{
T m[N];
T &operator[](int n) { return m[n]; }
};
template<class T>
struct vector<T, 1>
{
T m;
T &operator[](int) { return m; }
operator T &() { return m; }
};
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Ben Hutchings Guest
|
Posted: Wed Sep 22, 2004 6:51 pm Post subject: Re: enable_if like behaviour for conversion operators |
|
|
Jaap Suter wrote:
| Quote: | Hi,
consider the following code:
template<class T, int N
struct vector
{
T m[N];
};
Now, I'd like to make the following compile:
vector
scalar[0] = 1.0f;
float f = scalar;
But this should not compile:
vector<float, 2> v;
float f = v;
Does anybody have any ideas on how this can be achieved?.
snip |
You could use a partial specialisation of the template:
template<class T>
struct vector<T, 1>
{
T m[1];
operator T() const { return m[0]; }
// I assume these are also defined in the main template
// in the code you're really using.
T & operator[](std::size_t i)
{ assert(i == 0); return m[0]; }
T operator[](std::size_t i) const
{ assert(i == 0); return m[0]; }
};
--
Ben Hutchings
Larkinson's Law: All laws are basically false.
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Jonas.Latt@cui.unige.ch Guest
|
Posted: Wed Sep 22, 2004 6:55 pm Post subject: Re: enable_if like behaviour for conversion operators |
|
|
Jaap Suter wrote:
| Quote: | template<class T, int N
struct vector
{
T m[N];
};
Now, I'd like to make the following compile:
vector
scalar[0] = 1.0f;
float f = scalar;
But this should not compile:
vector<float, 2> v;
float f = v;
|
Try partial template specialization:
#include <cassert>
using namespace std;
template<class T, int N>
class vector
{
public:
T& operator[](unsigned index) {
assert(index < N);
return m[index];
}
private:
T m[N];
};
template
class vector<T,1>
{
public:
operator T() { return m; }
T& operator[](unsigned index) {
assert(index==0);
return m;
}
private:
T m;
};
int main() {
vector<int, 1> v1;
vector<int, 2> v2;
v1[0] = 1;
int i = v1;
v2[1] = 1;
}
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Jaap Suter Guest
|
Posted: Thu Sep 23, 2004 8:01 am Post subject: Re: enable_if like behaviour for conversion operators |
|
|
Thanks for the replies everybody!
Using PTS directly, as most of you suggested is not really feasible in
my code because in reality vector is a class spanning over 300 lines
of code. I would rather not duplicate that. Impossible to see from my
example of course.
Aside: does anybody ever use specialization for classes bigger than 20
lines anyway? I don't see any use, unless it's for optimizations
related to built-in types perhaps.
Of course, I would indirectly (through mpl::if_) have used PTS with my
suggestion of selectively injecting the function with a base class.
I like Rob Williscroft's version the best. Thanks Rob!
Cheers,
Jaap Suter
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Old Wolf Guest
|
Posted: Thu Sep 23, 2004 8:04 am Post subject: Re: enable_if like behaviour for conversion operators |
|
|
[email]J.Suter (AT) student (DOT) utwente.nl[/email] (Jaap Suter) wrote:
| Quote: |
template<class T, int N
struct vector
{
T m[N];
};
Now, I'd like to make the following compile:
vector
scalar[0] = 1.0f;
float f = scalar;
But this should not compile:
vector<float, 2> v;
float f = v;
|
Others have suggested a partial specialization of the entire class,
but this would be annoying if the class was more complicated.
My idea was to only specialize the case <T, 1> , so that
other cases would get a linker error.
I tried:
template<class T, int N>
struct vector
{
T m[N];
operator T();
};
template<class T>
vector<T, 1>::operator T() { return m[0]; }
but got lots of compiler errors. Is this not allowed, or is
my compiler wrong? It worked to go:
vector<float, 1>::operator float() { return m[0]; }
The errors were:
e.cc:12: error: invalid use of undefined type `struct vector<T, 1>'
e.cc:4: error: declaration of `struct vector<T, 1>'
e.cc:12: error: template definition of non-template `vector<T, 1>::operator T()'
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Ben Hutchings Guest
|
Posted: Fri Sep 24, 2004 3:29 pm Post subject: Re: enable_if like behaviour for conversion operators |
|
|
Old Wolf wrote:
<snip>
| Quote: | Others have suggested a partial specialization of the entire class,
but this would be annoying if the class was more complicated.
My idea was to only specialize the case <T, 1> , so that
other cases would get a linker error.
I tried:
template<class T, int N
struct vector
{
T m[N];
operator T();
};
template
vector
but got lots of compiler errors. Is this not allowed, or is
my compiler wrong?
snip |
It's not allowed; there's no such thing as a partial specialisation of
a function.
I came up with what I think is a good solution: where N == 1, define
operator T and where N > 1, define the useless operator void instead.
using boost::mpl::if_c;
template<class T, int N>
struct vector
{
T m[N];
typedef typename if_c<N == 1, T, void>::type scalar_type;
operator scalar_type() { return scalar_type(m[0]); }
};
If the OP does not want to use Boost, if_c can be defined thus:
template<bool, typename true_type, typename false_type>
struct if_c
{
typedef false_type type;
};
template<typename true_type, typename false_type>
struct if_c<true, true_type, false_type>
{
typedef true_type type;
};
--
Ben Hutchings
Who are all these weirdos? - David Bowie, about L-Space IRC channel #afp
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Glen Low Guest
|
Posted: Sat Sep 25, 2004 10:37 am Post subject: Re: enable_if like behaviour for conversion operators |
|
|
| Quote: | Using PTS directly, as most of you suggested is not really feasible in
my code because in reality vector is a class spanning over 300 lines
of code. I would rather not duplicate that. Impossible to see from my
example of course.
Aside: does anybody ever use specialization for classes bigger than 20
lines anyway? I don't see any use, unless it's for optimizations
related to built-in types perhaps.
|
You can put common functionality in a base class and have partial
specializations inherit from that to avoid repeating those 300 lines
of code.
My current favorite trick is to use SFINAE via enable_if:
template <typename T, typename Enable = void> struct X
{
...
};
template <typename T> struct X <T, typename enable_if * some
condition */>::type>:
public X <T, int>
{
...
};
or, without the use of enable_if,
template <typename T> struct X <T*, void>: public X <T*, int>
{
...
};
thus, the primary template serves as both the common base class and
the default case.
Cheers,
Glen Low, Pixelglow Software
www.pixelglow.com
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
James Hopkin Guest
|
Posted: Sat Sep 25, 2004 10:38 am Post subject: Re: enable_if like behaviour for conversion operators |
|
|
[email]J.Suter (AT) student (DOT) utwente.nl[/email] (Jaap Suter) wrote in message news:<5e7a0d2.0409212040.552c2d1 (AT) posting (DOT) google.com>...
| Quote: |
Mmm, come to think of it, perhaps I can selectively derive from a base
class based on the 'N' parameter. The 1-dimensional base class injects
the proper operator overload, and the others don't. Seems like a nasty
approach (the member array needs to move to the base class then)
though.
|
On second thoughts, you might be onto something here (although I still
think my other suggestion is the cleanest solution all round).
How about:
struct empty_base {};
template <typename T, typename V>
struct supply_conversion
{
public:
operator T&() { return static_cast<V&>(*this).m[0];
}
operator const T&() const { return static_cast<const
V&>(*this).m[0]; }
protected:
~supply_conversion() {}
};
template <typename T, int N>
class vector : public boost::if_c<
1 == N,
supply_conversion
N> >,
empty_base
friend class supply_conversion<T, vector>;
T m[N];
//...
};
James
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
James Hopkin Guest
|
Posted: Sat Sep 25, 2004 10:42 am Post subject: Re: enable_if like behaviour for conversion operators |
|
|
[email]google (AT) jaapsuter (DOT) com[/email] (Jaap Suter) wrote in message news:<da2e12e5.0409221640.77015610 (AT) posting (DOT) google.com>...
| Quote: |
I like Rob Williscroft's version the best. Thanks Rob!
|
I'd just note that Rob's implementation will cause
boost::is_convertible (and equivalents) to return a false positive
(the conversion exists - it just causes a compiler error when you try
to use it).
I think the best solution is to implement vector's functionality in
terms of functions that only take T as a template parameter (not N).
This will avoid significant potential code bloat.
It also allows
template <class T, int n> struct vector;
template <class T> struct vector<T, 1>;
as suggested by other people, to be implemented entirely consisting of
trivial forwarding functions.
James
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Alberto Barbati Guest
|
Posted: Sat Sep 25, 2004 6:34 pm Post subject: Re: enable_if like behaviour for conversion operators |
|
|
Ben Hutchings wrote:
| Quote: |
I came up with what I think is a good solution: where N == 1, define
operator T and where N > 1, define the useless operator void instead.
using boost::mpl::if_c;
snip
|
That's quite an interesting use of mpl::if_c. Thanks for the suggestion!
However, I think I found a not-so-ugly way to have no operator at all:
template<class T, int N>
struct basic_vector
{
T m[N];
};
template<class T, int N>
struct vector : basic_vector<T, N>
{};
template<class T>
struct vector<T, 1> : basic_vector<T, 1>
{
operator T();
};
You can't partially specialize a single member, but you can partially
specialize the entire class. Just move the common code into a base!
Hope it helps,
Alberto
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Terje Slettebų Guest
|
Posted: Sun Sep 26, 2004 9:48 am Post subject: Re: enable_if like behaviour for conversion operators |
|
|
| Quote: | From: "Terje Slettebų"
|
"Jaap Suter" <J.Suter (AT) student (DOT) utwente.nl> wrote
| Quote: | You may want to adjust the various access
specifiers (struct was used, since it was used in the example above).
|
Here's a possibly more industrial-strength version of the code in my
previous posting:
template<class T>
class conversion_helper {};
template<template
class conversion_helper<TT
{
public:
typedef TT<T,1> derived;
operator T&() { return static_cast<derived *>(this)->m[0]; }
protected:
~conversion_helper() {}; // Prevent deletion through pointer to base class
};
template<class T,size_t N>
class vector : public conversion_helper<vector
{
public:
T& operator[](size_t i) { return m[i]; }
// Rest of implementation
private:
T m[N];
friend class conversion_helper<vector;
};
int main()
{
vector<float,1> scalar;
scalar[0] = 1.0;
float f = scalar;
vector<float,2> v;
//float g = v; // Error
}
Regards,
Terje
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Terje Slettebų Guest
|
Posted: Sun Sep 26, 2004 9:48 am Post subject: Re: enable_if like behaviour for conversion operators |
|
|
"Jaap Suter" <J.Suter (AT) student (DOT) utwente.nl> wrote
| Quote: | Hi,
consider the following code:
template<class T, int N
struct vector
{
T m[N];
};
Now, I'd like to make the following compile:
vector
scalar[0] = 1.0f;
float f = scalar;
But this should not compile:
vector<float, 2> v;
float f = v;
Does anybody have any ideas on how this can be achieved?. I tried
coming up with ways to use enable_if, but it seem useless for
conversion operators.
|
In addition to the other suggestions in this thread, you might consider
using a variant of the "curiously recurring template" (aka
self-parameterised base class) pattern:
template<class T>
struct conversion_helper {};
template<template
struct conversion_helper<TT
{
typedef TT<T,1> derived;
operator T&() { return static_cast<derived *>(this)->m[0]; }
};
template<class T, size_t N>
struct vector : conversion_helper<vector
{
T& operator[](size_t i) { return m[i]; }
// Rest of implementation
T m[N];
};
int main()
{
vector<float, 1> scalar;
scalar[0] = 1.0;
float f = scalar;
vector<float, 2> v;
//float g = v; // Error
}
This avoids is_convertible returning incorrectly true, and also avoids the
need for forwarding functions. You may want to adjust the various access
specifiers (struct was used, since it was used in the example above).
Regards,
Terje
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
|