Using type defined inside templated type - c++

Is there any nice way to do the following?
/* vvv */
template<typename Wrapper> using T = typename Wrapper::type
T f(const T &a, const T &b) {
return a + b;
}
where Wrapper is some class which contains (several) types defined inside of it.
I can do the following, but I don't like this approach as it makes the function have several templated types (and also does not have the exact same meaning):
template<typename Wrapper, typename T = typename Wrapper::type>
T f(..)
I want to do this purely to reduce boilerplate of typing typename Wrapper::type in the function declaration. If there is a better way to do this, please let me know.
Note: in my project the Wrapper type needs to satisfy some concept, which also requires having the type type defined inside the type Wrapper.
If it may help, here is my use case. I am (attempting) to write a linear algebra library. In this scenario, in order to create objects such as vectors or matrices, we need to supply a field F, which must satisfy:
F is over some elementary type T (available by e.g., F::type)
F is supplied with two operations OpAdd and OpMul, both of which can operate on T.
Defining this using concepts is simple, however this adds some clutter, such as my example above.

Do you know what the type will be? If so you can supply the template argument:
template<class T>
using inner = typename T::type;
template<class T>
inner<T> f(inner<T> const& a, inner<T> const& b);
// ...
f<X>(y, y);

In requested circumstances, what you don't like is the only solution
#include <type_traits>
template<typename Wrapper,
typename T = typename Wrapper::type,
typename std::enable_if<std::is_same<T, typename Wrapper::type>::value>::type* = nullptr>
T f(const T &a, const T &b) {
return a + b;
}
struct S {
typedef long type;
};
int main() {
f<S>(0L, 0L); // ok
// f<S>(0, 0); // failure
// If the second type is set explicitly
f<S, long>(0L, 0L); // ok
f<S, long>(0, 0); // ok
// f<S, int>(0L, 0L); // failure
// f<S, int>(0, 0); // failure
}
This is a better solution than one with inner<T>, because f<S>(0, 0) will not fail with inner<T> - the exact long is required but int is passed.

Related

dependent types without helper type

Given typename T and int N, the templated value below generates a null function pointer of the type:
int (*) (T_0, ..., T_N)
While the code works, I don't like that it pollutes the namespace with the Temp bootstrap helper - Temp is required because types can't be enclosed in parentheses. For example, none of the following are valid.
(int (*)((int))
((int (*)(int)))
(int (*)( (I,T)... ))
The last entry shows how I would like to expand T into a list of N Ts - which of course isn't valid. It's a trick to make T depend on I but with a value only of T, thanks to the comma operator.
As a workaround, I'm forced to create the one-shot type Temp templated to make T depend on int, or in this case, I. Its usage as Temp<T,I> is valid because it doesn't enclose types in parenthesis.
However, like I said, I want to get rid of Temp because it pollutes the namespace. In the code below I restate the problem and demonstrate some attempted workarounds which sadly, all fail. For the record, I think an equivalence between template <typename T, int> using Temp = T; and template <... template<typename T1, int N1> typename Temp=T> should be allowed.
Followup: When I original published this question, I didn't know exactly why extra parentheses were disallowed, and I'm still not sure why some of my attempts failed. For example:
decltype(w<T,N>())...
result_of<w<T,N>()>::type...
I don't see any parentheses around types!
#include <iostream>
#include <typeinfo>
// Problem, #1
// This is a one-shot helper than pollutes the namespace
template <typename T, int>
using Temp = T;
// Idea #1
// Make the one-shot helper actuall useful, where ... represents either
// type or non-type parameters.
// Result
// Not possible.
//template <typename T, ...>
//using Dependent = T;
// Idea #2
// Make the types dependent within the template declaration
// Result
// Probably not possible
//template <typename T, int N, template<typename T1, int N1> typename F=T>
// Idea #6
// Replace the lambda with a struct (not shown)
// Result
// Crashes gcc
template <typename T, int N>
auto a =
[]<size_t... I>
(std::index_sequence<I...>) {
// Problem #2
// Function type declaration won't parse with extra parentheses
//return (int (*)( (I,T)... ))nullptr;
// Idea #3
// Move the templated helper into the function
// Result
// Not possible
//template <typename T, int>
//using Temp = T;
// Idea #4
// Replace the templated helper with a templated lambda which *is*
// allowed inside functions.
// Result
// Still requires parentheses, still breaks function type declaration
//auto w = []<typename T1, int N1>() -> T1 {};
//return (int (*)( decltype(w<T,N>())... ));
// Idea #5
// result_of (which is a template) instead of decltype
// Result
// Doesn't work even without parentheses, not sure why
//return (int (*)( result_of<w<T,N>>... ));
//return (int (*)( result_of<w<T,N>()>::type... ));
// Idea #7
// Use std::function
// Result
// Can't get function pointer from std::function
// Idea #2 implementation
//using F<T,I> = T;
//return (int (*)( F<T,I>... ))nullptr;
// So far, only this works:
return (int (*)( Temp<T,I>... ))nullptr;
}
(std::make_index_sequence<N>{});
int main () {
auto b = a<int, 4>;
std::cout << typeid(b).name() << std::endl;
}
You can replace Temp<T,I> with std::enable_if_t<(void(I), true), T>.
Function type declarations won't parse extra parentheses
that actually works! Why?
Types can't be enclosed in parentheses. But the first argument of enable_if_t is an expression rather than a type, so ( ) is allowed there.
This is pretty easy with Boost.Mp11:
template <typename... Args>
using into_func = int(Args...);
template <typename T, size_t N>
using result = mp_apply<func_type, mp_repeat_c<mp_list<T>, N>>;
mp_repeat_c<mp_list<T>, N> gives us mp_list<T, T, T, ..., T> with N parameters, and then we mp_apply into_func on that, which turns it into the function type we want.
As to why a few of your other versions didn't work:
This one:
decltype(w<T,N>())...
where:
auto w = []<typename T1, int N1>() -> T1 {};
That's not how you call that lambda. The call operator is a template, but you can't provide the template parameters like that. You have to write w.operator()<T, N>(). If you did that, that probably works.
Or you could do:
auto w = [](size_t) -> T { };
And then use decltype(w(N))....
Although it would be better to write something closer to a valid lambda, like:
auto w = [](size_t) { return std::type_identity<T>{}; };
And then use typename decltype(w(N))::type...
This approach:
result_of<w<T,N>()>::type...
result_of is used like result_of<F(Args...)> where F is a function or function object type. For instance:
struct F { double operator()(int); };
result_of_t<F(int)>; // this is double
This just isn't anything like that here at all - it's just a misuse of result_of. result_of is also deprecated in favor of invoke_result, which wouldn't work with this lambda as specified anyway since again it takes template parameters rather than function parameters.
With my last rewrite tho:
typename std::invoke_result_t<decltype(w), decltype(N)>::type...
Note both the decltype(w) (since you need a type, not an object) and the decltype(N) (since again, type not value).

C++ function with unlimited parameters but with the same (fixed) type

I want to have a function with unlimited number of parameters but I want also make sure that those are all pointers of the same type. Something like this:
void myFunc(float value, MyClass* ....)
{
// take all pointers of type MyClass and call function `f` like this: a->(value);
// store pointer in a vector like: vector.push_back(a);
}
Can I achieve this in C++?
void myFunc(float value, std::initializer_list<MyClass*> il){
for(auto* p:il)
p->f(value);
}
no heap/free store allocation will occur.
Use is myFunc(3.14, {ptr1,ptr2,ptr3});
If you really hate {} you can forward to the above with an unrestricted template. At the point of forwarding there will be type checking. SFINAE can be used to type check earlier.
template<class...MyClasses>
void myFunc2( float value, MyClasses*... ps) {
myFunc( value, {ps...} );
}
(possibly with name changes)
Alternatively, full SFINAE based solutions can be done, with direct calling of p->f, bit that is like using a bazooka to deal with litter. Sure, the litter will be gone, but it was still a bad idea.
initializer lists are designed for efficient bundling of parameters of identical type.
Now, a good question to ask about your MyClass* request is ... why do you care? If the passed in parameters are compatible with ->f(3.14f), why not just call ->f(3.14f)? This is why practical problems are better problems to ask about, rather than abstract ones: the best solution to a problem varies with practical issues.
The bazooka solution looks like the follows.
First, a small template metaprogramming library:
// Better name for the type:
template<bool b>
using bool_t = std::integral_constant<bool, b>;
// bundle of types:
template<class...>struct types{using type=types;};
// takes a test, and a types<?...> of things to test against it:
template<template<class...>class Z, class args>
struct test_lists:std::true_type{};
template<template<class...>class Z, class...Ts, class...Us>
struct test_lists<Z,types<types<Ts...>,Us...>>:bool_t<
Z<Ts...>{} && test_lists<Z, types<Us...>>{}
>{};
// takes 0 or more types<?...> and concatenates them:
template<class...types>
struct concat_types;
template<class...types>
using concat_types_t=typename concat_types<types...>::type;
template<>
struct concat_types<>:types<>{};
template<class...Ts>
struct concat_types<types<Ts...>>:types<Ts...>{};
template<class...T0s,class...T1s, class...more>
struct concat_types<types<T0s...>,types<T1s...>,more...>:
concat_types_t< types<T0s...,T1s...>, more... >
{};
// takes a template Z and and arg, and produces a template
// equal to Z<Arg, ?...>:
template<template<class...>class Z, class Arg>
struct bind_1st {
template<class...Ts>
using apply=Z<Arg,Ts...>;
};
// takes a template Z and a types<?...> and produces
// types< Z<?>... >:
template<template<class...>class Z, class types>
struct map;
template<template<class...>class Z, class types>
using map_t=typename map<Z,types>::type;
template<template<class...>class Z, class...Ts>
struct map<Z,types<Ts...>>:types<Z<Ts>...>{};
// builds a cross product of zero or more types<?...>:
template<class...types0>
struct cross_types;
template<class...types>
using cross_types_t=typename cross_types<types...>::type;
// valid degenerate cases:
template<class...Ts>
struct cross_types<types<>,Ts...>:types<>{};
template<>
struct cross_types<>:types<types<>>{};
// meat of cross_types:
template<class T0, class...T0s, class...Us>
struct cross_types<types<T0,T0s...>, Us...>:
concat_types_t<
map_t< bind_1st< concat_types_t, types<T0> >::template apply, cross_types_t<Us...> >,
cross_types_t< types<T0s...>, Us... >
>
{};
// takes a test Z, and a sequence of types<?...> args
// tests the cross product of the contents of the args:
template<template<class...>class Z, class...Args>
struct test_cross : test_lists<Z, cross_types_t<Args...>> {};
everything above this point is generic metaprogramming code. You can do the next part more directly, but the generic metaprogramming code above can be used in other similar problems, and it does make the later stuff "clearer".
// a toy MyClass type to test against:
struct MyClass {
void f(float x){
std::cout << x << '\n';
}
};
// Simple SFINAE test that the types passed in are exactly
// pointers to MyClass:
template<class...Ts>
std::enable_if_t<
test_cross<std::is_same, types<MyClass>, types<Ts...>>{}
>
myFunc( float x, Ts*... p ) {
using discard=int[];
(void)discard{0,((
p->f(x)
),void(),0)...};
}
note that std::is_base_of might be a better choice than is_same.
The core is here:
test_cross<std::is_same, types<MyClass>, types<Ts...>>{}
this evaluates std::is_same<A,B> for every pair of <MyClass, Ts>.
A far easier way to do it would be a template that took a bunch of bool... and did an && on them, together with std::is_same<MyClass, Ts>{}.... But I like writing metaprogramming libraries, and doing n-way cross product tests with brevity is a more interesting problem.
live example
Cross product based off of this stack overflow answer in python
You could do the following, then you can stick to your existing syntax..
#include <iostream>
#include <type_traits>
using namespace std;
struct V
{
int a;
int b;
};
// Little test function to ensure that it's the type we're expecting..
template <typename T>
int test(T*)
{
static_assert(is_same<T, V>::value, "Must only be V");
return 0;
}
template <typename ...T>
void foo(int a, T*... args)
{
// Use expansion to test all the parameters, this will generate
// an error if the wrong type is passed in
auto v = { (test(args), 0)... };
(void) v; // result discarded..
}
int main()
{
V a, b, c, d, e;
int f;
foo(10, &a, &b, &c, &d, &e, &f); // this will fail
foo(10, &a, &b, &c, &d, &e); // this will compile
}
Basically use the a parameter pack with a static_assert to force the type to be the same...

Cast function type to differ if types of arguments are convertable

I am writing a wrapper class for callable types (pointer to function, functors, etc). I want to implement something like std::function.
I define constructor from pointer to function:
template <typename Ret, typename... Args>
class function<Ret(Args...)>
{
public:
function(Ret (func)(Args...))
{
m_fn_ptr = func;
}
}
Now, let's assume that i want to use my class like this:
int int_function(int n)
{
return n;
}
function<int(short)> wrapper(&int_function); // compile error
Despite that short are implicit convertable to int compiler cannot deduce template parameters and call appropriate constructor.
Then i tried this:
template <typename FRet, typename... FArgs>
function(FRet (func)(FArgs...))
{
m_fn_ptr = static_cast<Ret (*f)(Args...)>(func);
}
But I got invalid static cast.
How can I fix that ?
The super_func is a function object with no state that can convert to any compatible call signature.
template<class T>using type=T;
template<class Sig, Sig* func>
struct super_func;
template<class R, class...Args, R(*func)(Args...)>
struct super_func<R(Args...), func> {
using Sig = R(Args...);
using pSig = Sig*;
template<class R2, class...Args2, std::enable_if_t<
std::is_convertible<
std::result_of_t<pSig(Args2...)>,
R2
>{}
&& !std::is_same<R2, void>{},
bool
> =true>
constexpr operator type<R2(Args2...)>*() const {
return [](Args2...args)->R2{
return func(std::forward<Args2>(args)...);
};
}
template<class...Args2, std::enable_if_t<
std::is_same<
std::result_of_t<pSig(Args2...)>,
R
>{},
bool
> =true>
constexpr operator type<void(Args2...)>*() const {
return [](Args2...args)->void{
func(std::forward<Args2>(args)...);
};
}
constexpr operator pSig() const {
return func;
}
constexpr R operator()(Args...args)const{
return func(std::forward<Args>(args)...);
}
};
live example. A super_func is stateless. To use it on a function foo, do:
super_func< decltype(foo), &foo > super_foo;
and you get a callable stateless empty object which behaves a lot like foo does, except you can assign it to a pointer to any compatible function pointer and it generates it "on the fly" at compile time.
A super_foo can be fed to your function object.
Doing this on the fly doesn't work without the exterior help, as we need the foo to be a truly static bit of information. By the time it becomes a variable, it is too late to do this statelessly, so we cannot use the lambda trick (without an extra pvoid) to generate a function pointer for the exact signature we want.
You could do a macro:
#define SUPER(X) super_func< decltype(X), &X >{}
and then create your function object with function<double()> f(SUPER(foo));
Another approach is to store an extra pointer's worth of state, and create "the fastest possible delegate" style type erasure. (that term can be googled for one of many implementations, each faster than the last).
How can I fix that ?
Use the correct types when creating wrapper.
Instead of using
function<int(short)> wrapper(&int_function);
use
function<int(int)> wrapper(&int_function);
Remember that class templates instantiated with int and short are very different types and are not convertible to each other.
template <typename T> struct Foo {};
Foo<int> a;
Foo<short> b = a; // Not OK.
Foo<short> c;
Foo<int> d = c; // Not OK.
Your function constructor expects a pointer to a function that takes a short, not an int. The fix is to provide it such a function. The easiest way to do that is to use a lambda with an empty capture-list, that is implicitly convertible to a function pointer:
function<int(short)> wrapper( [](short s) { return int_function(s); } );

Express general monadic interface (like Monad class) in C++

Is it even possible to express a sort of monad" C++ ?
I started to write something like this, but stuck:
#include <iostream>
template <typename a, typename b> struct M;
template <typename a, typename b> struct M {
virtual M<b>& operator>>( M<b>& (*fn)(M<a> &m, const a &x) ) = 0;
};
template <typename a, typename b>
struct MSome : public M<a> {
virtual M<b>& operator>>( M<a>& (*fn)(M<a> &m, const a &x) ) {
return fn(*this, x);
}
private:
a x;
};
M<int, int>& wtf(M<int> &m, const int &v) {
std::cout << v << std::endl;
return m;
}
int main() {
// MSome<int> v;
// v >> wtf >> wtf;
return 0;
}
but faced the lack of polymorphism. Actually it may be my uncurrent C++ 'cause I used it last time 8 years ago. May be it possible to express general monadic interface using some new C++ features, like type inference. It's just for fun and for explaining monads to non-haskellers and non-mathematicians.
C++' type system is not powerful enough to abstract over higher-kinded types, but since templates are duck-typed you may ignore this and just implement various Monads seperately and then express the monadic operations as SFINAE templates. Ugly, but the best it gets.
This comment is bang on the money. Time and time again I see people trying to make template specializations 'covariant' and/or abuse inheritance. For better or for worse, concept-oriented generic programming is in my opinion* saner. Here's a quick demo that will use C++11 features for brevity and clarity, although it should be possible to implement the same functionality in C++03:
(*: for a competing opinion, refer to "Ugly, but the best it gets" in my quote!)
#include <utility>
#include <type_traits>
// SFINAE utility
template<typename...> struct void_ { using type = void; };
template<typename... T> using Void = typename void_<T...>::type;
/*
* In an ideal world std::result_of would just work instead of all that.
* Consider this as a write-once (until std::result_of is fixed), use-many
* situation.
*/
template<typename Sig, typename Sfinae = void> struct result_of {};
template<typename F, typename... Args>
struct result_of<
F(Args...)
, Void<decltype(std::declval<F>()(std::declval<Args>()...))>
> {
using type = decltype(std::declval<F>()(std::declval<Args>()...));
};
template<typename Sig> using ResultOf = typename result_of<Sig>::type;
/*
* Note how both template parameters have kind *, MonadicValue would be
* m a, not m. We don't whether MonadicValue is a specialization of some M<T>
* or not (or derived from a specialization of some M<T>). Note that it is
* possible to retrieve the a in m a via typename MonadicValue::value_type
* if MonadicValue is indeed a model of the proper concept.
*
* Defer actual implementation to the operator() of MonadicValue,
* which will do the monad-specific operation
*/
template<
typename MonadicValue
, typename F
/* It is possible to put a self-documenting assertion here
that will *not* SFINAE out but truly result in a hard error
unless some conditions are not satisfied -- I leave this out
for brevity
, Requires<
MonadicValueConcept<MonadicValue>
// The two following constraints ensure that
// F has signature a -> m b
, Callable<F, ValueType<MonadicValue>>
, MonadicValueConcept<ResultOf<F(ValueType<MonadicValue>)>>
>...
*/
>
ResultOf<MonadicValue(F)>
bind(MonadicValue&& value, F&& f)
{ return std::forward<MonadicValue>(value)(std::forward<F>(f)); }
// Picking Maybe as an example monad because it's easy
template<typename T>
struct just_type {
using value_type = T;
// Encapsulation omitted for brevity
value_type value;
template<typename F>
// The use of ResultOf means that we have a soft contraint
// here, but the commented Requires clause in bind happens
// before we would end up here
ResultOf<F(value_type)>
operator()(F&& f)
{ return std::forward<F>(f)(value); }
};
template<typename T>
just_type<T> just(T&& t)
{ return { std::forward<T>(t) }; }
template<typename T>
just_type<typename std::decay<T>::type> make_just(T&& t)
{ return { std::forward<T>(t) }; }
struct nothing_type {
// Note that because nothing_type and just_type<T>
// are part of the same concept we *must* put in
// a value_type member type -- whether you need
// a value member or not however is a design
// consideration with trade-offs
struct universal { template<typename T> operator T(); };
using value_type = universal;
template<typename F>
nothing_type operator()(F const&) const
{ return {}; }
};
constexpr nothing_type nothing;
It is then possible to write something like bind(bind(make_just(6), [](int i) { return i - 2; }), [](int i) { return just("Hello, World!"[i]); }). Be aware that the code in this post is incomplete in that the wrapped values aren't forwarded properly, there should be errors as soon as const-qualified and move-only types are involved. You can see the code in action (with GCC 4.7) here, although that might be a misnomer as all it does is not trigger assertions. (Same code on ideone for future readers.)
The core of the solution is that none of just_type<T>, nothing_type or MonadicValue (inside bind) are monads, but are types for some monadic values of an overarching monad -- just_type<int> and nothing_type together are a monad (sort of -- I'm putting aside the matter of kind right now, but keep in mind that it's possible to e.g. rebind template specializations after the fact, like for std::allocator<T>!). As such bind has to be somewhat lenient in what it accepts, but notice how that doesn't mean it must accept everything.
It is of course perfectly possible to have a class template M such that M<T> is a model of MonadicValue and bind(m, f) only ever has type M<U> where m has type M<T>. This would in a sense make M the monad (with kind * -> *), and the code would still work. (And speaking of Maybe, perhaps adapting boost::optional<T> to have a monadic interface would be a good exercise.)
The astute reader would have noticed that I don't have an equivalent of return here, everything is done with the just and make_just factories which are the counterparts to the Just constructor. This is to keep the answer short -- a possible solution would be to write a pure that does the job of return, and that returns a value that is implicitly convertible to any type that models MonadicValue (by deferring for instance to some MonadicValue::pure).
There are design considerations though in that the limited type deduction of C++ means that bind(pure(4), [](int) { return pure(5); }) would not work out of the box. It is not, however, an insurmountable problem. (Some outlines of a solution are to overload bind, but that's inconvenient if we add to the interface of our MonadicValue concept since any new operation must also be able to deal with pure values explicitly; or to make a pure value a model of MonadicValue as well.)
I would do it like this:
template<class T>
class IO {
public:
virtual T get() const=0;
};
template<class T, class K>
class C : public IO<K> {
public:
C(IO<T> &io1, IO<K> &io2) : io1(io1), io2(io2) { }
K get() const {
io1.get();
return io2.get();
}
private:
IO<T> &io1;
IO<K> &io2;
};
int main() {
IO<float> *io = new YYYY;
IO<int> *io2 = new XXX;
C<float,int> c(*io, *io2);
return c.get();
}

C++ Template problem adding two data types

I have a template class with an overloaded + operator. This is working fine when I am adding two ints or two doubles. How do I get it to add and int and a double and return the double?
template <class T>
class TemplateTest
{
private:
T x;
public:
TemplateTest<T> operator+(const TemplateTest<T>& t1)const
{
return TemplateTest<T>(x + t1.x);
}
}
in my main function i have
void main()
{
TemplateTest intTt1 = TemplateTest<int>(2);
TemplateTest intTt2 = TemplateTest<int>(4);
TemplateTest doubleTt1 = TemplateTest<double>(2.1d);
TemplateTest doubleTt2 = TemplateTest<double>(2.5d);
std::cout << intTt1 + intTt2 << /n;
std::cout << doubleTt1 + doubleTt2 << /n;
}
I want to be able to also do this
std::cout << doubleTt1 + intTt2 << /n;
Stephen has already given a good explanation of the problems you may encounter with this. You can define overloads for all the possible combinations of all the instantiations of the template (so, you'd effectively have operators defined for double + double, int + double, double + int, etc.). This can get unwieldy fast and can be difficult to keep track of which combinations are supported.
You might be better off using a non-member function named something like Add(). The advantage of doing this is that you can specify the return type. The disadvantage is that you have to specify the return type. :-) In general, though, this is better than performing unexpected conversions automatically.
template <typename R, typename T, typename U>
TemplateTest<R> Add(const TemplateTest<T>& t, const TemplateTest<U>& u)
{
return TemplateTest<R>(t.x + u.x);
}
invoked as:
std::cout << Add<double>(intTt1, doubleTt1) << std::endl;
C++0x will add support for a number of language features that will make this much simpler and will allow you to write a reasonable operator+ overload:
template <typename T, typename U>
auto operator+(const TemplateTest<T>& t, const TemplateTest<U>& u)
-> TemplateTest<decltype(t.x + u.x)>
{
return TemplateTest<decltype(t.x + u.x)>(t.x + u.x);
}
This will ensure that the usual arithmetic conversions (integer promotion, conversion to floating point, etc.) are performed and you end up with the expected result type.
Your C++ implementation may support these C++0x features already; you'd want to consult the documentation of whatever compiler you are using.
Here be dragons. You're getting into parts of c++ that will probably result in a lot of questions posted to StackOverflow :) Think long and hard about if you really want to do this.
Start with the easy part, you want to allow operator+ to add types that are not always the same as T. Start with this:
template <typename T2>
TemplateTest<T> operator+(const TemplateTest<T2>& rhs) {
return TemplateTest<T>(this->x + rhs.x);
}
Note that this is templated on T2 as well as T. When adding doubleTt1 + intTt2, T will be doubleTt1 and T2 will be intTt2.
But here's the big problem with this whole approach.
Now, when you add a double and an int, what do you expect? 4 + 2.3 = 6.3? or 4 + 2.3 = 6? Who would expect 6? Your users should, because you're casting the double back to an int, thus losing the fractional part. Sometimes. Depending on which operand is first. If the user wrote 2.3 + 4, they would get (as expected?) 6.3. Confusing libraries make for sad users. How best to deal with that? I don't know.
I want to be able to also do this
std::cout << doubleTt1 + intTt2 << "\n";
What you'll probably need for this case are type traits. Basically, those are template classes containing typedefs. You then partially specialize such a template to override the typedefs.
Basic example:
(This is probably a bit naïve, but it should get the basic idea across.)
template <typename A, typename B>
struct add_traits
{
typedef A first_summand_t; // <-- (kind of an "identity type")
typedef B second_summand_t; // <-- (ditto; both aren't strictly necessary)
typedef B sum_t; // <-- this is the interesting one!
};
Now you partially specialize that thing for various combinations of A and B:
template<>
struct add_traits<int, int>
{
typedef int first_summand_t;
typedef int second_summand_t;
typedef int sum_t; // <-- overrides the general typedef
};
template<>
struct add_traits<int, double>
{
typedef int first_summand_t;
typedef double second_summand_t;
typedef double sum_t; // <-- overrides the general typedef
};
template<>
struct add_traits<double, int>
{
typedef double first_summand_t;
typedef int second_summand_t;
typedef double sum_t; // <-- overrides the general typedef
};
Now you could write a fairly generic add operation that went like this:
template <typename A, typename B>
typename add_traits<A,B>::sum_t add(A first_summand, B second_summand)
{
// ...
}
As you can see, you don't specify a concrete return type; instead, you let the compiler figure it out through the add_traits template class. Once the compiler generates the code for a particular add function, it will look up the types in the corresponding add_traits class, and thanks to the partially specialized versions that you provided, you can make sure that certain type "combinations" will be applied.
P.S.: The same technique would e.g. also be useful when you want to subtract unsigned numbers. One unsigned int subtracted from another can result in a negative answer; the result type would have to be a (signed) int.
P.P.S.: Corrections made according to the comments below.
The add operator should generally be a free function to avoid preferring any operand type as #Stephen nicely explains. This way it's completely symmetric. Assuming you have a function get that returns the stored value, this can be like the following (alternatively, you can declare it as a friend if such a get function does not exist)
template<typename T1, typename T2>
TemplateTest<???> operator+(const TemplateTest<T1>& t1, const TemplateTest<T2>& t2)
{
return TemplateTest<???>(t1.get() + t2.get());
}
The problem now is to find a result type. As other answers show this is possible with decltype in C++0x. You can also simulate this by using the rules of the ?: operator which are mostly quite intuitive. promote<> is a template that uses that technique
template<typename T1, typename T2>
TemplateTest< typename promote<T1, T2>::type >
operator+(const TemplateTest<T1>& t1, const TemplateTest<T2>& t2)
{
return TemplateTest< typename promote<T1, T2>::type >(t1.get() + t2.get());
}
Now for example if you add double and int, it will yield double as the result. Alternatively as shown in the promote<> answer, you can also specialize promote so you can apply it directly to TemplateTest types.
If this is mainly for basic types, you could help yourself with a metafunction until the new standard rolls in. Something along the lines of
template<typename T1,
typename T2,
bool T1_is_int = std::numeric_limits<T1>::is_integer,
bool T2_is_int = std::numeric_limits<T2>::is_integer,
bool T1_is_wider_than_T2 = (sizeof(T1) > sizeof(T2)) > struct map_type;
template<typename T1, typename T2, bool b> struct map_type<T1, T2, b, b, true > { typedef T1 type; };
template<typename T1, typename T2, bool b> struct map_type<T1, T2, b, b, false> { typedef T2 type; };
template<typename T1, typename T2, bool b> struct map_type<T1, T2, false, true , b> { typedef T1 type; };
template<typename T1, typename T2, bool b> struct map_type<T1, T2, true , false, b> { typedef T2 type; };
template<typename T, typename U>
typename map_type<TemplateTestT<T>, TemplateTest<U> >::type
operator+(TemplateTest<T> const &t, TemplateTest<U> const &u) {
return typename map_type<TemplateTest<T>, TemplateTest<U> >::type(x + t1.x);
}
Of course, this is best combined with the char_traits idea:
template <typename A, typename B>
struct add_traits
{
typedef A first_summand_t;
typedef B second_summand_t;
typedef typename map_type<A, B>::type sum_t;
};
So that you can still specialise for types that don't have a numeric_limits overload.
Oh, and in production code, you'll probably want to properly namespace that and add something for signed/unsigned mismatches in integer types.
Get a compiler that supports the new C++0x decltype operator.
template < typename T1, typename T2 >
auto add(T1 t1, T2 t2) -> decltype(t1+t2)
{
return t1 + t2;
}
Now you don't have to fart around with those "traits" classes.
You can add int and double values by using templates.In the function, specify 2 arguments and while passing values to the functions specify its types in angular brackets.
example:
//template
template<typename T1, typename T2>
void add(T1 a, T2 b)
{
//for adding values
cout<<"\n\nSum : "<<a+b;
}
int main ()
{
//specify types while passing values to funcion
add<int,double>(4,5.5454);
add<float,int>(4.7,5);
add<string,string>("hi","bye");
return 0;
}
Newer answer to an old question.
For C++0x you can go with decltype as other answers have talked about.
I would argue that common_type is more made for the situation than decltype.
Here is an example of common_type used in a generic add:
#include <iostream>
#include <array>
#include <type_traits>
using namespace std;
template <typename T, typename U, unsigned long N>
array<typename common_type<T, U>::type, N> // <- Gets the arithmetic promotion
add_arrays(array<T, N> u, array<U, N> v)
{
array<typename common_type<T, U>::type, N> result; // <- Used again here
for (unsigned long i = 0; i != N; ++i)
{
result[i] = u[i] + v[i];
}
return result;
}
int main()
{
auto result = add_arrays( array<int, 4> {1, 2, 3, 4},
array<double, 4> {1.0, 4.23, 8.99, 55.31} );
for (size_t i = 0; i != 4; ++i)
{
cout << result[i] << endl;
}
return 0;
}
it basically returns the value that different arithmetic operations would promote to. One nice thing about it is that it can take any number of template args. Note: don't forget to add the ::type at the end of it. That is what gets the actual type result that you want.
For those working pre-c++11 still, there is a boost version of common_type as well
This is technically possible by defining an implicit case to TemplateTest<double>:
operator TemplateTest<double>() {
return TemplateTest<double>((double)x);
}
Practically this probably isn't a great idea though, as x can't necessarily be safely cast to a double; it happens that you're using a TemplateTest<int> here, but you could be using a TemplateTest<std::string> later. You should probably rethink what you're doing and decide if you're sure you actually need this behavior