Template for return-type
-
Hello again!
I have a great problem, which can be demonstrated in a simple code.
Imagine, that I want to write
Sqr(x)
function, which shouldreturn x*x
for every type of argumentx
havingoperator*
:template<class T> inline T Sqr(T const &x) { return x*x; }
But that function does not work for every type of
x
. It works only for those types, which produces the same type by multiplication. I cannot use this function, for example, for vectors, where vector*vector==scalar (“scalar product”).I want to have something like this:
template<class T> inline ReturnTypeOf(T::operator*(T)) Sqr(T const &x) { return x*x; }
or this:
template<class T> inline [Dear compiler! See type of my return operator! I have only one such operator.] Sqr(T const &x) { return x*x; }
P.S.: #define works for this case, but it does not work, for example, for overloaded operators.
-
template<class T, class TR> inline TR Sqr(T const &x) { return x*x; }
also does not work
. Compiler error “Cannot deduce template parameter for TR” when trying to call such a function.
-
Currently, there is no general solution for this problem. Here we need to determine the type from an expression without evaluating that expression (in order to use it in a declaration), however, some compilers do have extensions to make that possible (__typeof). If the set of possible types is known, a solution exists using some nifty template techniques in conjunction with sizeof. In that case, boost's typeof library is viable:
// helper-template, no definition required template<typename T> const T& make(); // BOOST_TYPEOF_TPL( T() * T() ) cannot handle types that are not default-constructible template<typename T> BOOST_TYPEOF_TPL( make<T>() * make<T>() ) sqr(const T& x) { return x * x; }
In the upcoming standard, this problem shall have an elegant solution:
template<typename T> constexpr sqr(T&& x) -> decltype( x * x ) { return x * x; }
-
you could provide a helper template
teplate <typename T> struct SquaredType { typedef T ResultType; //normally T*T gives another T }; template<> struct SquaredType<3DVector> { typedef Scalar ResultType; //Product of 2 3DVector gives a Scalar }; template <typename T> SquaredType<T>::ResultType Sqr(T const& x) {return x*x;}
now you only have to specialize SquaredType for types where the multiplication gives another type
-
Thanks. How to use __typeof technique?
I thinked for several days and thinked out the following solution:
class cVector { ... public: template<class C> struct tMult{}; template<> struct tMult<cVector>{typedef double type;}; //The type of vector*vector template<> struct tMult<double>{typedef cVector type;}; //The type of vector*double ... };
Now, for all classes which have
tMult
struct I can do the following:template<class A, class B> inline typename A::tMult<B>::type Multiply(A const &a, B const &b) { return a*b; }
P.S.: Why “typedef template is illegal” ?? Why I need to store type in template struct?
-
SAn schrieb:
TP.S.: Why “typedef template is illegal” ?? Why I need to store type in template struct?
Good question. It just is. Again, the next standard will have a solution to this problem (albeit not using the keyword 'typedef' but rather a templated 'using'). At the moment the best way to work around this restriction is by using meta functions – those 'template struct' constructs.
-
-
Konrad Rudolph schrieb:
SAn schrieb:
TP.S.: Why “typedef template is illegal” ?? Why I need to store type in template struct?
Good question. It just is. Again, the next standard will have a solution to this problem (albeit not using the keyword 'typedef' but rather a templated 'using'). At the moment the best way to work around this restriction is by using meta functions – those 'template struct' constructs.
Though even with template aliases you need meta functions in their declarations if these aliases shall, depending on their template parameters, refer to template classes and ordinary types.
.filmor schrieb:
That does not apply here because result_of requires a call-expression, using an operator does not necessarily result in a function call.
-
camper schrieb:
In the upcoming standard, this problem shall have an elegant solution:
template<typename T> constexpr sqr(T&& x) -> decltype( x * x ) { return x * x; }
for the sake of syntacical correctness:
template <typename T> auto constexpr sqrt (T&&x) -> decltype( x*x ) { return x*x; }
-
SAn schrieb:
Thanks. How to use __typeof technique?
depends on how your compiler implements it.
possibly either this way:template <class T> typeof (T() + T()) //or that way (preferably): typeof (*static_cast<T*>(0) + *static_cast<T*>(0)) foo (T const& a, T const& b) { return a + b; }
-
Was ist denn jetzt der Unterschied zwischen tr1::result_of und decltype ?
Fragt
Werner
-
decltype funktioniert immer, nicht nur mit funktionen.
int a(1), b(2), c(3); decltype (a + b * c) d; //int d; decltype (a = 5) e; //int& e; - operator= gibt eine referenz zurück
result_of wird in C++0x übrigens mittels decltype implementiert sein.
(btw. schreibe ich gerade für das magazin einen artikel über die neuen sprachfeatures von C++0x, also einfach bis nächste woche warten
)
-
Hi SAn,
SAn schrieb:
template<class T, class TR> inline TR Sqr(T const &x) { return x*x; }
also does not work
. Compiler error “Cannot deduce template parameter for TR” when trying to call such a function.
I think the order ist wrong.
template<class TR, class T> inline TR Sqr(T const &x) { return x*x; } int main() { int i = 3; double d = Sqr<double>(i); }
If you want the return value it must be on the first place. Then you must explicit determine the first template and the second parameter is deduced by the compiler.
BR,
Markus