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.
Related
This is my code:
#include<iostream>
struct Item {
int val;
};
struct XItem {
int val;
};
void transform(const Item &i, XItem &target) {
target.val = i.val;
}
template<typename T>
void show(const T &v) {
std::cout << v.val << std::endl;
}
template<typename ParamsType, typename ResultType>
void handleRequest(Item &cur, ResultType (*impl)(const ParamsType &p)) {
ParamsType p{};
transform(cur, p);
ResultType res = (*impl)(p);
show(res);
}
struct ResItem {
int val;
};
int main(int argc, char *argv[]) {
Item i{42};
handleRequest(i, [](const XItem &x) {
return ResItem{x.val};
});
return 0;
}
Compiling it gives the following error:
test.cpp:33:3: error: no matching function for call to 'handleRequest'
handleRequest(i, [](const XItem &x) {
^~~~~~~~~~~~~
test.cpp:21:6: note: candidate template ignored: could not match 'ResultType
(*)(const ParamsType &)' against '(lambda at test.cpp:33:20)'
void handleRequest(Item &cur, ResultType (*impl)(const ParamsType &p)) {
^
I am unsure why this happens, however I do suspect that because the lambda, while being implicitly convertible to a function pointer, isn't one, the template parameters can't be deduced from it.
I tried using std::function<ResultType(const ParamsType &p)> instead, which also doesn't work. This question details the problem, so I tried to use its solution:
template<typename ParamsType, typename ResultType, typename Callback>
void handleRequest(Item &cur, Callback cb) {
ParamsType p = transform(cur);
ResultType res = std::invoke(cb, p);
show(res);
}
However, now ParamsType and ResultType cannot be implicitly deduced from the callback, I would need to give them explicitly. But I really want to infer ResultType because in the actual code, it can be quite lengthy (it is inferred from the lambda return statement, which is more complex than in this minimal example). I need the two types because both transform and show are overloaded and need the types to bind.
Is it possible to have handleRequest infer those types in this scenario and if so, how?
The problem is, implicit conversion (from lambda to function pointer) is not considered in template argument deduction, which fails deducing the template parameters.
Type deduction does not consider implicit conversions (other than type adjustments listed above): that's the job for overload resolution, which happens later.
You can specify the template arguments explicitly to bypass the deduction,
handleRequest<XItem, ResItem>(i, [](const XItem &x) {
return ResItem{x.val};
});
Or convert the lambda to function pointer explicitly,
handleRequest(i, static_cast<RestItem(*)(const XItem&)>([](const XItem &x) {
return ResItem{x.val};
}));
Or use the operator+ to convert the lambda to function pointer.
handleRequest(i, +[](const XItem &x) {
return ResItem{x.val};
});
What is the reason of the following rule, "a user-defined conversion function template cannot have a deduced return type."
struct S {
operator auto() const { return 10; } // OK
template<class T> operator auto() const { return 42; } // error
};
Even if it was allowed, in the second line, there is nothing that depends on the template.
It can't be called (what is the purpose of T in that case ?)
If you want to convert to a user defined type, then you'll do that:
Let's say you have:
struct S
{
template<typename T> operator T() { return T(42); }
};
That's clear and there is no need to deduce anything.
You'd call this like this:
S s;
int v = s;
float f = s;
Please notice that, in that case, using auto instead of float in the code above would prevent the compiler to deduce the type (is it a float ? an int ? an Orange ?). The sentence above simply explains that.
I'm trying to override the << operator but it seems that the compiler doesn't recognize my implementation and instead tries to interpret it as a bit shift.
I've already tried to play around with the parameter types (const T&, T&, T, const T) to no avail.
#pragma once
template<typename T> class AbstractStack
{
public:
virtual bool Push(const T &) = 0;
}
template <typename T> class ArrayStack : public AbstractStack <T>
{
public:
bool Push(const T&) {
....
}
}
template <typename T> bool operator<<(const AbstractStack<T>* &, const T&) {
return stack->Push(item);
}
int main() {
AbstractStack<int> *stack = new ArrayStack<int>(5);
int a = 2;
stack << a; // <<-- compiler error
return 0;
}
The error reported is:
Error (active) expression must have integral or unscoped enum type Lab10
Error C2296 '<<': illegal, left operand has type 'AbstractStack<int> *'
If I define the same operator acting on the class as a value, it just works...
When overloading operators, at least one of the arguments must be a class or an enum type - basically this allows/limits you to overloading custom types (user defined types).
From the cppreference;
When an operator appears in an expression, and at least one of its operands has a class type or an enumeration type, then overload resolution is used to determine the user-defined function to be called among all the functions whose signatures match the following...
This makes sense in that it disallows you from overloading the built in types; in this case, the pointer and integer you have as arguments.
As you already remarked in the question, the solution is taking your first argument by reference;
template <typename T>
bool operator<<(AbstractStack<T> &, const T&)
{ //...
Given the abstract base class you are looking to use, you could investigate the use of std::shared_ptr to help manage the resources and make the use of a "pointer" in the overloaded operator (albeit it will be a smart pointer);
template <typename T>
bool operator<<(std::shared_ptr<AbstractStack<T>>&, const T&)
{
return stack->Push(item);
}
int main() {
std::shared_ptr<AbstractStack<int>> stack = std::make_shared<ArrayStack<int>>(5);
int a = 2;
stack << a;
return 0;
}
As others have said, overloading any builtin operator requires an object of a user-defined type; a pointer won't work. And the solution is to use an object instead of a pointer:
template <typename T> bool operator<<(AbstractStack<T>&, const T&) {
return stack.Push(item);
}
and then call it with an object. There's no good reason in the code you've shown to allocate from the free-store; just create an auto object:
int main() {
ArrayStack<int> stack(5);
int a = 2;
stack << a;
return 0;
}
I have been struggling with this one for about a half day and it seem that at least XCode 4.6 has a bug where certain declaration of template class would violate the language and allow to pass const data from within class to external functions with parameters delcared as without const modifiers.
The example below WILL COMPILE, even tough template declaration of
Tcaller::call() method specifies const arguments passed as reference
but static cmp function is providing useless *const & modifiers.
template< typename T> struct Tcalled
{
// !!!error - this prototype doesn't protect the data passed to function
// because it should be declared with const modifiers but it wouldn't compile then.
// SEE: Below my NOTE for correct function prototype.
static bool cmp(const Tcalled*& item, const int& key) //<- correct but doesn't work
static bool cmp(Tcalled* const & item, const int& key) //<- invalid but works!!
{
return (item->index = key); /// error - we modify const object here !
}
T index;
};
template < typename T> struct Tcaller
{
Tcaller(){}
template < typename K, bool (*compare)(const T& item, const K& key) >
bool call(int k) const { return compare(data, k); }
T data;
};
int main(int argc, char *argv[])
{
const Tcaller<Tcalled<int>* > tmp; // <- const data
int k = 1;
tmp.call<int,Tcalled<int>::cmp>(k); //call here WILL modify const data !!
}
And the question : HOW I can force XCode to obey the rules and allow me to prototype
my static function as it was declared for template parameter ? As for now these are the errors from XCode I get when I declare my static method correctly :
No matching member function for call to 'call'
Candidate template ignored: invalid explicitly-specified argument for template parameter 'compare'
Thanks!
Presumably you mean that it works when the argument is declared as Tcalled<T>* const & item and the body of cmp should be using == not =.
You have a misunderstanding about the way template arguments are instantiated. It's not just a copy-paste substitution of the template arguments. You're expecting that const T& when instantiated with T as Tcalled<int>* will be equivalent to const Tcalled<int>*&; that is, a "reference to pointer to const Tcalled<int>.
However, this is wrong, the const applies to the whole T type. So really, after instantiation, const T& is equivalent to Tcalled<int>* const&. This is why having the argument declared as Tcalled* const & item works fine.
To get this to work with the declaration as const Tcalled<T>*& item, a number of things have to change:
The call function template arguments should be defined like so:
template < int (*compare)(T& item) >
That is, the function pointer type takes a T&, not a const T&. This makes sense as the cmp function does not take a reference to const object at all (it takes a reference to non-const pointer).
The call function should not be const:
int call() { return compare(data); }
This is because it's passing its member T to compare, which is a reference to non-const object (the pointer itself is not const). It can't do that if it is a const function because it cannot guarantee that compare won't modify the object.
Tcaller must be instantiated with T as const Tcalled<int>*:
Tcaller<const Tcalled<int>* > tmp;
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
}