Determine type of argument - c++

Is it somehow possible to reflect the type of the argument of a function at compile time?
So that
int b = add(3, 6)
Would result in a template instantiation in the form of
int add(int a, int b) { return a + b }
out of some however declared function template
A add(A a, B b) { return a + b }
I don't know if that is possible with templates they do not really seem to be made for heavy meta-programming.

template<typename T>
T add(T a, T b) { return a + b; }
Then you can call this with any built-in type (int, short, double, float, etc), and it will instantiate the function add at compile time, according to the type you use.
Note that if you split this into header/source, you will have trouble:
add.h:
template<typename T>
T add(T a, T b);
add.cpp:
template<typename T>
T add(T a, T b) { return a + b; }
main.cpp:
#include "add.h"
int a = 3;
int b = 5;
int i = add(a, b);
When you try to compile this, it will fail at link time. Here's why.
Compiling add.obj does not instantiate the add template method -- because it's never called in add.cpp. Compiling main.obj instantiates the function declaration -- but not the function body. So at link time, it will fail to find the definition of the add method.
Simplest fix is to just put the entire template function in the header:
add.h:
template<typename T>
T add(T a, T b) { return a + b; }
and then you don't even need the add.cpp file at all.

Doesn't this do what you're asking?
template <typename A, typename B>
A add(A a, B b) { return a + b; }
This is hardly "heavy meta-programming".

This is exactly the sort of thing templates do.
template <typename T>
inline T add(T a, T b) { return a + b; }
Allowing two different types gets a little bit trickier but is also possible.

If you plan on using anything other than simple types you want (in a header file):
template <typename A>
inline A add(const A& a, const A& b) { return a + b; }
Note the 'inline'.
As noted by others, the issue with mixed types is how to determine the return type from the argument types. Suppose we stick to simple types and have:
template
inline A add(A a, B b) { return a + b; }
Then this fails (likely with only a warning):
double d = add(1, 1.5); // Sets d to 2.0
So you have to do some work. For example:
template<class A, class B>
struct Promote
{
};
template<class A>
struct Promote<A,A>
{
typedef A Type;
};
template<>
struct Promote<int, double>
{
typedef double Type;
};
template<>
struct Promote<double, int>
{
typedef double Type;
};
The add function becomes:
template<class A, class B>
inline typename Promote<A,B>::Type add(A a, B b)
{
return a + b;
}
What all this does for you is ensure that the return type is the one you specify for adding a given pair of types. This will work even for complex types.

Templates do all their magic at compile time, but that seems to be quite adequate for what you're asking:
template <class T>
T add(T a, T b) { return a + b; }
It does get a bit more complex when the two might not match, so (for example) you could add an int to a double and get a double result. The current standard doesn't really support that1; with C++0x you can look into auto and decltype for such tasks.
1Though Boost typeof will often do the job.

Related

How to implicitly cast all arguments of a template function to the highest resolution type?

In a project I'm working on I have a templated function similar to this where all of the arguments should be of type T
#include <iostream>
template<typename T> bool aWithinBOfC(T a, T b, T c)
{
return std::abs(a - c) < b;
}
the issue I'm having is it won't compile if all of the arguments are not of the same type but it seems reasonable that it should implicitly cast similar types to the one with the highest resolution before evaluation. Is there any way to get a call like this to be valid?
int main()
{
double a{1.2};
double b{1.4};
float c{0.1f};
std::cout << aWithinBOfC(a, b, c) << std::endl;
}
Something along these lines, perhaps:
template<typename T>
bool aWithinBOfCImpl(T a, T b, T c) {
/* actual implemenattion */
}
template <typename ... Args>
auto aWithinBOfC(Args... args) {
return aWithinBOfCImpl<std::common_type_t<Args...>>(args...);
}
Demo
You don’t need implicit conversions at the call site. The compiler will implicitly convert the types to the largest one in the expression in the return statement.
template <class T, class U, class V>
bool aWithinBOfC(T a, U b, V c) {
return std::abs(a - c) < b;
}

Disambiguate recursive definition of template function

I am building a statically typed Matrix where all operations with matrices are typechecked. However, I am having issues when I want to do something that modifies the Matrix based on given number.
For instance, adding one column is trivial:
template<int A, int B>
Matrix<A,B+1> addOneCol(Matrix<A,B> m1) {
return Matrix<A,B+1>();
}
However, adding N columns is way harder. Since is impossible to typecheck with a function that has a branch where the return type is not the expected (even if the branch condition guarantees it) I can only think about a recursive approach:
template<int A, int B, int Z>
Matrix<A,B+1> addZCols(Matrix<A,B> m1) {
return addOneCol(m1);
}
template<int A, int B, int Z>
Matrix<A,B+Z> addZCols(Matrix<A,B> m1) {
return addOneCol(addZCols<A,B,Z-1>(m1));
}
template<int A, int B>
Matrix<A,B+1> addOneCol(Matrix<A,B> m1) {
return Matrix<A,B+1>();
}
However, this is overloading addZCols in the return type, what is not allowed and leads to an error saying that calling addZCalls is ambiguous and cannot chose one of the 2 candidates. And what I want is that the version wiht B+1 is only called as the base case, so to speak, when Z=1.
Any idea about how to make this work or a different approach?
If I understand your requirement correctly, you could simply write the function template like this:
template<int A, int B, int Z = 1>
Matrix<A,B+Z> addZCols(Matrix<A,B> m1) {
return Matrix<A,B+Z>{};
}
and then use it like this:
Matrix<1,2> a = addZCols(Matrix<1,1>{});
Matrix<1,4> b = addZCols<1,1,3>(Matrix<1,1>{});
By default, the 3rd parameter is 1, and so this function template can be used as addOneCol.
As #Evg points out, template parameters have the nice property that default arguments can appear in any order, so we could have the Z argument in the first position:
template<int Z = 1, int A, int B>
Matrix<A,B+Z> addZCols(Matrix<A,B> m1) {
return Matrix<A,B+Z>{};
}
This allows you to make the call more conveniently, like this:
Matrix<1,2> a = addZCols(Matrix<1,1>{});
Matrix<1,4> b = addZCols<3>(Matrix<1,1>{});
Since only Z needs to be specified, as A, and B can be deduced from the Matrix argument.
There may be a more efficient approach, but with the recursion solution that you proposed, SFINAE can be used to disambiguate the two versions of the template function.
#include <type_traits>
template <int A, int B>
struct Matrix {
constexpr int rows() const { return A; }
constexpr int cols() const { return B; }
int data;
};
template<int Z, int A, int B, std::enable_if_t<Z == 0, int> = 0>
Matrix<A, B> addZCols(Matrix<A,B> m1) {
return m1;
}
template<int Z, int A, int B, std::enable_if_t<Z != 0, int> = 0>
Matrix<A,B+Z> addZCols(Matrix<A,B> m1) {
return addOneCol(addZCols<Z-1, A, B>(m1));
}
template<int A, int B>
Matrix<A,B+1> addOneCol(Matrix<A,B> m1) {
return Matrix<A,B+1>();
}
int main() {
Matrix<2, 2> m1;
auto m2 = addZCols<3>(m1);
static_assert(m2.rows() == 2, "check rows");
static_assert(m2.cols() == 5, "check cols");
return 0;
}
I have also offset the recursion limit by one for clarity and re-ordered the template parameters of addZCols to make it nicer to call, but it works just the same with your original signature.

Covering legacy C style functions using C++ template

I have the following two functions in C.
float floatAdd(float a, float b)
{
return a+b;
}
double doubleAdd(double a, double b)
{
return a+b;
}
Now, I would like to combine both functions and write a tempalte function in C++ as follows.
template<class T>
T add(T a, T b)
{
// if T=float, return floatAdd(a,b)
// if T=double, return doubleAdd(a,b)
}
Since the return types are different, I am unable to find a solution!
Please note that the above functions are very simple, and used as merely an example. My intention is provide a C++ template wrapper for some Legacy C functions the kind explained the example.
Your example doesn't really show the need to use the specific functions. But in a more general case, you can provide a specific implementation for a template function or template class for a given set of template arguments. The feature is known as Template specialization and is specifically designed to address this problem.
template<class T>
T add(T a, T b);
// Special implementation for floatAdd
template<>
float add<float>(float a, float b)
{
return floatAdd(a, b);
}
// Special implementation for floatDouble
template<>
double add<double>(double a, double b)
{
return doubleAdd(a, b);
}
For such a simple case, you can simply use a regular template :
template<class T>
T add(T a, T b)
{
return a + b;
}
If you don't care about supporting a general case, you can just use function overloading and forget about templates :
float add(float a, float b)
{
return floatAdd(a, b);
}
double add(double a, double b)
{
return doubleAdd(a, b);
}

Give nullptr a type for template deduction

Suppose the following snippet:
template <class T>
void fct(T* a, T* b){
// do something
}
A a;
fct(&a, nullptr); // Problem here!
This makes trouble, since the call arguments are of type A* and nullptr_t and so the compiler can not deduce template parameter T.
Generally, I can imagine several ideas how to solve this:
Define A* b = nullptr and use fct(&a, b)
Define an overload with one argument for fct for the nullptr case
Use fct(&a, static_cast<A*>(nullptr))
Or is there a more clean solution, like the creation of a something like a "typed nullptr"?
Just make the second argument a non-deduced context, e.g:
template <class T>
void fct(T* a, std::remove_reference<T*>::type b) {
I would also suggest the following solution:
template <class T, class U>
void fct(T* a, U b){
T* b2 = b;
// do something
}
A a;
fct(&a, nullptr);
This allows for a wider usage of fct, but maybe that's exactly what you want to.
For example, consider
class A {};
class B : public A {};
...
A a;
B b;
fct(&a, &b); // calls fct<A>
// the following will not compile:
// fct(&b, &a);
You can use the following code:
#include <type_traits>
template<class T>
void f_impl(T*, T*)
{
std::cout << typeid(T).name() << "\n";
}
template<class T, class U>
void f(T l, U r)
{
static_assert((std::is_same<T, U>::value && std::is_pointer<T>::value) ||
(std::is_same<T, std::nullptr_t>::value && std::is_pointer<U>::value) || // First non-null
(std::is_same<U, std::nullptr_t>::value && std::is_pointer<T>::value) // Second non-null
, "");
using P = typename std::conditional<std::is_same<T, std::nullptr_t>::value, U, T>::type;
f_impl<typename std::remove_pointer<P>::type>(l, r);
}
int main()
{
int i;
f(&i, nullptr);
f(nullptr, &i);
// f(i, nullptr); // won't compile - non-pointer
f(&i, &i);
double d;
// f(&i, &d); // - won't compile
}
This version tests will allow to call f with one nullptr (but not both), or with two pointers to the same type. With c++14 you can also use things like std::conditional_t, std::remove_pointer_t and std::is_null_pointer to remove some biolerplate.
As the question already states, nullptr in fact has a type: std::nullptr_t. So just add an explicit overload for specifically that case:
template <class T>
void fct(T* a, std::nullptr_t b) { return fct<T>(a,static_cast<T*>(b)); }
No need to have some template argument class U for that.

Comparing == != in templates

What is the correct way to perform == and != operators in template classes?
Assume this code:
template<typename T>
class C {
T x, y;
public:
C(T a, T b) : x(a), y(b) {}
bool cmp() {
return x == y;
}
};
int main()
{
// OK
C<int> i(1,2);
i.cmp();
// not OK
C<double> d(1.0, 2.0);
d.cmp();
return 0;
}
If you build it with g++ -Wfloat-equal, you'll get
warning: comparing floating point with == or != is unsafe
[-Wfloat-equal]
because you can't simply compare float variables.
Update
I've solved the problem using type_traits and enable_if like this (thanks #Andrew and #OMGtechy):
#include <type_traits>
#include <limits>
#include <cmath>
#include <iostream>
using namespace std;
template <typename IntegralType>
typename std::enable_if<std::is_integral<IntegralType>::value, bool>::type
equal(const IntegralType& a, const IntegralType& b) {
return a == b;
}
template <typename FloatingType>
typename std::enable_if<std::is_floating_point<FloatingType>::value, bool>::type
equal(const FloatingType& a, const FloatingType& b) {
return std::fabs(a-b) < std::numeric_limits<FloatingType>::epsilon();
}
template<typename T>
class C {
T x, y;
public:
C(T a, T b) : x(a), y(b) {}
bool cmp() {
return equal(x, y);
}
};
int main()
{
// OK
C<int> i(1,2);
cout << i.cmp() << endl;
// not OK
C<double> d(1.0, 1.0);
cout << d.cmp() << endl;
return 0;
}
This question seems to be asking two things:
How can I do floating point comparisons without using operator==, and
how can I modify the behaviour of a template depending on the type passed to it.
One answer to the second question is to use type traits. The code below demonstrates this for your situation, providing a comparison_traits for general types (using ==) and a specialisation for doubles, using a tolerance (which answers the first question, too).
#include <cmath>
template <typename T> struct comparison_traits {
bool equal(const T& a, const T& b) {
return a == b;
}
// etc.
};
template<> struct comparison_traits<double> {
bool equal(const double& a, const double& b) {
return fabs(a - b) < 1e-15; // or whatever...
}
};
template <typename T>
class C {
T x, y;
public:
C(const T& a, const T& b) : x(a), y(b) {}
bool cmp() {
return comparison_traits<T>::equal(x, y);
}
};
int main() {
// OK
C<int> i(1, 2);
i.cmp();
// Now OK too...
C<double> d(1.0, 2.0);
d.cmp();
return 0;
}
Other options include:
Providing a template parameter that allows you to specify a comparison function, defaulting to std::equal_to
Specialising your template for double, so that you can write a different implementation of cmp()
It depends how it will be used. Comparing floats properly depends on the context.
I would recommend what #Niall says: add a comparator template parameter, defaulting to std::equal_to. This will allow callers to control how values are compared. See for example the docs on std::sort to see how a comparator parameter is used. The downside to this is that it's the caller's responsibility to account for comparing floats. If they forget, then they'll get the compiler warning you see.
Another option is template class specialization. Make a specialization for your class to deal specifically with float or double types, and compare them differently using whatever logic you prefer. Probably not the best solution though. The benefit to this is that callers no longer need to remember to specify a comparator.
If you ask why you get this warning:
here some example:
double a,b;
a=10.0/13.0;
b = a/3;
b*=3;
std::cout<<"a="<<a<<std::endl;
std::cout<<"b="<<b<<std::endl;
if(a!=b){
std::cout<<"NOT equal!!"<<std::endl;
std::cout<<"a-b="<<a-b<<std::endl;
}
else
std::cout<<"equal"<<std::endl;
if you'll do the math a and b are clearly equal.
but this is the output I've got:
a=0.769231
b=0.769231
NOT equal!!
a-b=-1.11022e-016
because it is not so accurate, a proper comparison for double should define some tolerancy:
for example(tolerancy may change according needs):
int compare(double a, double b)
{
double tolerancy = 0.000001;
if (abs(a-b) < tolerancy) return 0;
else if (a>b) return 1;
else /*if (a<b)*/ return -1;
}
and if I use this compare i get:
a=0.769231
b=0.769231
equal