I am just learning function templates and the template I created below doesn't compile and I am not sure what's wrong. I am trying to make an int variable and a double variable go into the template but I keep getting an error when I call the function. The error is:
error: no matching function for call to 'LargestFunction(int&, double&)'|
and the code is as follows:
template <class Temp>
Temp LargestFunction(Temp a, Temp b){
if(a > b){
return a;
}
else
return b;
}
int main()
{
int NumOne = 30;
double NumTwo = 52.252;
cout << LargestFunction(NumOne,NumTwo);
return 0;
}
If you want to support different types, you need to define the template with different template parameters.
template <typename Lhs, typename Rhs>
typename std::common_type<Lhs, Rhs>::type max(const Lhs &lhs, const Rhs &rhs) {
return lhs > rhs ? lhs : rhs;
}
This way you can pass different types and you'll get whatever the common type between them is.
If you want to only deal with equal types within the function, you can keep the template as-is.
template <typename T>
T max(const T &lhs, const T &rhs) {
return lhs > rhs ? lhs : rhs;
}
You need to then cast one of the parameters so that you have equal types.
max(static_cast<double>(101), 4.2);
Or, you could also explicitly specialize the function template, but this is discouraged in general.
max<double>(101, 4.2);
The compiler doesn't know which type it should infer. Should it be int or double? In your template, Temp refers to a single type. You are free to specify it by calling:
LargestFunction<double>(NumOne,NumTwo);
Or you could define your template to take Temp1 and Temp2 types.
Related
I am trying to built a templated num class. This class needs to have a public attribute, val, with type T, which is the only templated parameter. Furthermore if one provides a value the attribute (val) should be initialized with this value. To do so I made the following code:
#include <iostream>
template<class T>
class Num {
public:
T val;
Num():val(0) { std::cout<<"default constr used"<<std::endl; }
Num(T value):val(value) {std::cout<<"constr (T value) used"<<std::endl; }
~Num() { std::cout<<"destructor used"<<std::endl; }
template<typename U>
Num operator+(const Num<U>& other) {
return val+other.value;
}
};
Furthermore I created the main() function to test the program, which looks like this:
int main() {
std::cout << Num<int>(1) + Num<double>(2.0);
return 0;
}
However the result of the program is now 3. Whereas I expected it to be 3.0 (of type double).
For that you will need to change the return type.
In your code:
// vvv---- Means Num<T>
Num operator+(const Num<U>& other) {
return val + other.val;
}
Indeed, inside a class template, you can type the name of the class without template arguments and it's gonna be somewhat equivalent to writing Num<T>.
Your function is always returning the type of the first operant, no matter the type of the addition itself.
What you want is to deduce that type coming from the addition:
auto operator+(const Num<U>& other) -> Num<decltype(val + other.val)> {
return val + other.val;
}
That way, it's always the right return type according to the C++ operator rules.
operator+ should be symmetric with respect to its arguments. It's better be implemented as a free function rather than a member function to make this symmetry explicit.
For example (using C++14 return type deduction):
template<class T, class U>
auto operator+(const Num<T>& x, const Num<U>& y) {
using R = decltype(std::declval<T>() + std::declval<U>());
return Num<R>{x.val + y.val};
}
std::declval<T>() is there for genericity, if T and/or U are not default constructible. If types are limited to built-in ones, like int and double, it can be replaced with T{} or T():
using R = decltype(T{} + U{});
With class template argument deduction in C++17 it can be simplified further:
template<class T, class U>
auto operator+(const Num<T>& x, const Num<U>& y) {
return Num{x.val + y.val};
}
I'm trying to wrap my head around a copy assignment operator issue. I am at a loss what is really going on, though I have some ideas (listed at the end). This is a problem since I am using a 3rd party library with no control on its classes.
Lets say you have a templated container with copy assignment operator. This operator accepts another container with a different template, and tries to static_cast the other type.
template <class U>
vec2<T>& operator=(const vec2<U>& v) {
x = static_cast<T>(v.x);
y = static_cast<T>(v.y);
return *this;
}
This is fine for simple assignment, however when using references for T, you get a compile error about const value types. If you add another overload that accepts a non-const reference, it will compile and work.
I've made a simple example which should help illustrate the issue.
template <class T>
struct vec2 final {
vec2(T x_, T y_)
: x(x_)
, y(y_) {
}
template <class U>
vec2(const vec2<U>& v)
: x(static_cast<T>(v.x))
, y(static_cast<T>(v.y)) {
}
template <class U>
vec2<T>& operator=(const vec2<U>& v) {
if (this == &v)
return *this;
x = static_cast<T>(v.x);
y = static_cast<T>(v.y);
return *this;
}
// Fix :
/*
template <class U>
vec2<T>& operator=(vec2<U>& v) {
x = static_cast<T>(v.x);
y = static_cast<T>(v.y);
return *this;
}
*/
T x;
T y;
};
And how I am trying to use it :
int main(int, char**) {
vec2<int> v0 = { 0, 0 };
vec2<int> v1 = { 1, 1 };
vec2<int&> test[] = { { v0.x, v0.y }, { v1.x, v1.y } };
vec2<int> muh_vec2 = { 2, 2 };
test[0] = muh_vec2;
printf("{ %d, %d }\n", test[0].x, test[0].y);
return 0;
}
The latest AppleClang will generate the following error :
main4.cpp:18:7: error: binding value of type 'const int' to reference to type 'int'
drops 'const' qualifier
x = static_cast<T>(v.x);
^ ~~~
main4.cpp:63:10: note: in instantiation of function template specialization 'vec2<int
&>::operator=<int>' requested here
test[0] = muh_vec2;
^
What I understand from this, is that somehow the compiler is trying to assign by const value. But why and is there a non-intrusive solution to this issue?
I did find a similar question here : Template assignment operator overloading mystery
My conclusion after reading the issue is : maybe a default assignment operator is causing the issue? I still do not understand why though :/
Here is an online example : https://wandbox.org/permlink/Fc5CERb9voCTXHiN
template <class U>
vec2<T>& operator=(const vec2<U>& v)
within this method, v is a name for a const view of the right hand side. If U is int, then v.x is a const int.
If T is int&, then this->x is a int&.
this->x = static_cast<int&>(v.x);
this is obviously illegal: you cannot static cast a const int to a non const reference.
A general solution basically requires rebuilding the std::tuple or std::pair machinery. SFINAE can be used to bootstrap it. But in general, structs containing references and those containing values are usually quite different beasts; using one template for both is questionable.
template <class T>
struct vec2 final {
template<class Self,
std::enable_if_t<std::is_same<std::decay_t<Self>, vec2>>{}, bool> =true
>
friend auto as_tuple( Self&& self ){
return std::forward_as_tuple( std::forward<Self>(self).x, std::forward<Self>(self).y );
}
then we can do SFINAE tests to determine if as_tuple(LHS)=as_tuple(RHS) is valid.
Doing this for construction is another pain, as LHS's tuple type needs massage before the constructibility test can work.
The more generic you make your code, the more work it takes. Consider actual use cases before writing infinitely generic code.
I wrote a template to have a valid usage only when a struct, class has overloaded bool operator== otherwise compiler errors would come up,
namespace atn {
template <typename T>
bool find( std::vector<T>& cont, T find ) {
for( std::vector<T>::iterator it = cont.begin(); it != cont.end(); ++it ) {
if( (*it) == find )
return true;
}
return false;
}
};
So fine it is ok, for example:
struct sPlayer {
u_int idPlayer;
sPlayer() : idPlayer(0) {};
bool operator==( const sPlayer& ref ) const {
return ref.idPlayer == this->idPlayer;
};
};
int _tmain(int argc, _TCHAR* argv[]) {
std::vector<sPlayer>a;
sPlayer player;
player.idPlayer = 5;
a.push_back(player);
if(atn::find(a, player)){
std::cout << "Found" << std::endl;
}
return 0;
}
The thing is, if I use it this way:
vector<int>hold;
if(atn::find(hold, 4))
I got lost at this part, the templates assumes the type of T to be assigned at vector<T> by the value of the second parameter passed? Or it'll assume from the type of the vector reference passed?
Both arguments have to match. Template argument deduction tries to find a type for each template argument that makes the function argument types match the type of the supplied arguments.
Sometimes this gets a bit tricky, and things that should work don't. For example:
std::vector<int> v;
atn::find(v, 1U);
This fails, because the first argument wants to deduce T = int, but the second argument wants T = unsigned int. The deduction fails and the code doesn't compile. (If this is a problem, then the solution is to make all but one function argument non-deduced.)
the templates assumes the type of T to be assigned at vector by the value of the second parameter passed? or it'll assume from the type of the vector reference passed?
Neither. The compiler will infer the type of each of the arguments separately, and then it will verify that the inferred type is the same for all cases. If the inferred type is not the same for all arguments it will fail to compile.
One common example of this is the std::max (or std::min) template:
template <typename T>
T min( T lhs, T rhs ) {
return (lhs < rhs? lhs : rhs);
}
int main() {
min(1,1u); // error
}
Could any one tell why this function object doesn't need the specified the type?
class StringPtrTmplLess
{
public:
template<typename PtrType>
bool operator()(const PtrType * lhs, const PtrType * rhs)
{
return *lhs < *rhs;
}
};
int main()
{
set<string*, StringPtrTmplLess> s2;
return 0;
}
how does the compiler know which specified type it will initialize the StringPtrTmplLess with?
It is because of template argument deduction which means the template argument is deduced from the type of the argument passed to the function call. This type deduction is done by the compiler. Go through the link which explains it in great detail.
Please, consider the code below:
template<typename T>
bool function1(T some_var) { return true; }
template <typename T>
bool (*function2())(T) {
return function1<T>;
}
void function3( bool(*input_function)(char) ) {}
If I call
function3(function2<char>());
it is ok. But if I call
function3(function2());
compiler gives the error that it is not able to deduction the argument for template.
Could you, please, advise (give an idea) how to rewrite function1 and/or function2 (may be, fundamentally to rewrite using classes) to make it ok?
* Added *
I am trying to do something simple like lambda expressions in Boost.LambdaLib (may be, I am on a wrong way):
sort(some_vector.begin(), some_vector.end(), _1 < _2)
I did this:
template<typename T>
bool my_func_greater (const T& a, const T& b) {
return a > b;
}
template<typename T>
bool my_func_lesser (const T& a, const T& b) {
return b > a;
}
class my_comparing {
public:
int value;
my_comparing(int value) : value(value) {}
template <typename T>
bool (*operator<(const my_comparing& another) const)(const T&, const T&) {
if (this->value == 1 && another.value == 2) {
return my_func_greater<T>;
} else {
return my_func_greater<T>;
}
}
};
const my_comparing& m_1 = my_comparing(1);
const my_comparing& m_2 = my_comparing(2);
It works:
sort(a, a + 5, m_1.operator< <int>(m_2));
But I want that it doesn't require template argument as in LambdaLib.
Deduction from return type is not possible. So function2 can't be deduced from what return type you expect.
It is however possible to deduce cast operator. So you can replace function2 with a helper structure like: Unfortunately there is no standard syntax for declaring cast operator to function pointer without typedef and type deduction won't work through typedef. Following definition works in some compilers (works in G++ 4.5, does not work in VC++ 9):
struct function2 {
template <typename T>
(*operator bool())(T) {
return function1<T>;
}
};
(see also C++ Conversion operator for converting to function pointer).
The call should than still look the same.
Note: C++11 introduces alternative typedef syntax which can be templated. It would be like:
struct function2 {
template <typename T>
using ftype = bool(*)(T);
template <typename T>
operator ftype<T>() {
return function1<T>;
}
};
but I have neither G++ 4.7 nor VC++ 10 at hand, so I can't test whether it actually works.
Ad Added:
The trick in Boost.Lambda is that it does not return functions, but functors. And functors can be class templates. So you'd have:
template<typename T>
bool function1(T some_var) { return true; }
class function2 {
template <typename T>
bool operator()(T t) {
function1<T>;
}
};
template <typename F>
void function3( F input_function ) { ... input_function(something) ... }
Now you can write:
function3(function2);
and it's going to resolve the template inside function3. All STL takes functors as templates, so that's going to work with all STL.
However if don't want to have function3 as a template, there is still a way. Unlike function pointer, the std::function (C++11 only, use boost::function for older compilers) template can be constructed from any functor (which includes plain function pointers). So given the above, you can write:
void function3(std::function<bool ()(char)> input_function) { ... input_function(something) ... }
and now you can still call:
function3(function2());
The point is that std::function has a template constructor that internally generates a template wrapper and stores a pointer to it's method, which is than callable without further templates.
Compiler don't use context of expression to deduce its template parameters. For compiler, function3(function2()); looks as
auto tmp = function2();
function3(tmp);
And it don't know what function2 template parameter is.
After your edit, I think what you want to do can be done simpler. See the following type:
struct Cmp {
bool const reverse;
Cmp(bool reverse) : reverse(reverse) {}
template <typename T> bool operator()(T a, T b) {
return reverse != (a < b);
}
};
Now, in your operator< you return an untyped Cmp instance depending on the order of your arguments, i.e. m_2 < m_1 would return Cmp(true) and m_1 < m_2 would return Cmp(false).
Since there is a templated operator() in place, the compiler will deduce the right function inside sort, not at your call to sort.
I am not sure if this help you and I am not an expert on this. I have been watching this post since yesterday and I want to participate in this.
The template cannot deduce it's type because the compiler does not know what type you are expecting to return. Following is a simple example which is similar to your function2().
template<typename T>
T foo() {
T t;
return t;
};
call this function
foo(); // no type specified. T cannot be deduced.
Is it possible to move the template declaration to the class level as follows:
template<typename T>
bool my_func_greater (const T& a, const T& b) {
return a > b;
}
template<typename T>
bool my_func_lesser (const T& a, const T& b) {
return b > a;
}
template <typename T>
class my_comparing {
public:
int value;
my_comparing(int value) : value(value) {}
bool (*operator<(const my_comparing& another) const)(const T&, const T&) {
if (this->value == 1 && another.value == 2) {
return my_func_greater<T>;
} else {
return my_func_greater<T>;
}
}
};
and declare m_1 and m_2 as below:
const my_comparing<int>& m_1 = my_comparing<int>(1);
const my_comparing<int>& m_2 = my_comparing<int>(2);
Now you can compare as follows:
if( m_1 < m_2 )
cout << "m_1 is less than m_2" << endl;
else
cout << "m_1 is greater than m_2" << endl;
I know this is simple and everyone knows this. As nobody posted this, I want to give a try.