g++ with std=c++14 is giving me a "couldn't deduce template parameter ‘Key'" error, on a template method of a functor class (that isn't itself a template).
I can't figure out why. The code looks like it should work.
I am implementing a 2 3 tree, and it has a level order traversal method that takes a functor.
operator. The tree23 code is basically this:
template<class Key, class Value> class tree23 {
public:
class Node23 {
friend class tree23<Key, Value>;
public:
// snip...
friend std::ostream& operator<<(std::ostream& ostr, const Node23& node23)
{
// snip... outputs the keys and values of node23 to ostr.
}
private:
Node23 *parent;
std::array<Key, 2> keys;
std::array<Value, 2> values;
std::array<std::unique_ptr<Node23>, 3> children;
int totalItems; // either TwoNodeItems or ThreeNodeItems
// snip...
};
template<typename Functor> void levelOrderTraverse(Functor f) const noexcept;
// snip...
};
The level order traversal invokes the functor's function call operator, passing it two parameters.
template<class Key, class Value> template<typename Functor> \
void tree23<Key, Value>::levelOrderTraverse(Functor f) const noexcept
{
std::queue< std::pair<const Node23*, int> > queue;
Node23 *proot = root.get();
if (proot == nullptr) return;
auto initial_level = 1; // initial, top level is 1, the root.
queue.push(std::make_pair(proot, initial_level));
while (!queue.empty()) {
std::pair<const Node23 *, int> pair_ = queue.front();
const Node23 *current = pair_.first;
int current_tree_level = pair_.second;
// invokes functor's operator()(const Node23&, int)?
f(*current, current_tree_level);
if (!current->isLeaf()) {
for(auto i = 0; i < current->getChildCount(); ++i) {
queue.push(std::make_pair(current->children[i].get(), current_tree_level + 1));
}
}
queue.pop();
}
}
The functor is quite simple:
class levelOrderPrinter {
private:
// snip...
public:
levelOrderPrinter(std::ostream& ostr_lhs, int depth);
levelOrderPrinter(levelOrderPrinter&);
levelOrderPrinter(const levelOrderPrinter&);
template<class Key, class Value>
void operator()(const typename tree23<Key, Value>::Node23& node,
int current_level) noexcept;
};
template<class Key, class Value>
void levelOrderPrinter::operator()(const typename tree23<Key, Value>::Node23& node,
int current_level) noexcept
{
// Did level change?
if (level != current_level) {
level = current_level;
ostr << "\n\n" << "level = " << level;
// Provide some basic spacing to tree appearance.
std::size_t num = tree_depth - level + 1;
std::string str( num, ' ');
ostr << str;
}
ostr << node;
}
If you change the declaration of your function call operator like so:
template<class Node>
void levelOrderPrinter::operator()(const Node& node, int current_level) noexcept
Then the compiler will be able to deduce the type of Node.
In your original code:
template<class Key, class Value>
void levelOrderPrinter::operator()(const typename tree23<Key, Value>::Node23& node,
int current_level) noexcept
The compiler is not able to deduce the types Key or Value because tree23<Key, Value>::Node23 is a non-deduced context for Key and Value (§14.8.2.5), forcing you to use the explicit function template call syntax.
Changing this line
f(*current, current_tree_level);
in the method
template<class Key, class Value> template<typename Functor> \
void tree23<Key, Value>::levelOrderTraverse(Functor f) const noexcept
to be
f.template operator()<Key, Value>(*current, current_tree_level);
got rid of the "can't deduce template parameter” error. It isn't pretty but it now compiles.
Node23 is a nested type, and template parameters of its enclosing type cannot be deduced that easily. So you've had to specify them explicitly via template operator().
Related
I want to pass in a user defined function to a class which requires a user defined matching function. In ye olde days of C I would have used a function pointer with void* arguments. But there must be a better way...
Here is roughly the sort of thing I want to do. One limitation I have is that the platform I am on has no standard library. But the basic core language C++11 is available.
What I need to do:
#include <iostream>
using namespace std;
// TODO - replace this C construct with C++ equivalent
//typedef bool(*match_key)(const void* key1, const void* key2);
// somehow declare this as a typedef? need a way to declare a signature in C++
typedef template<class T>
bool (*match_key)(const T& key1, const T& key2);
// *** User defined matching function
bool mymatcher(const int i, const int j) {
return i == j;
}
template<class K>
class hashmap {
public:
hashmap<K>(const K& key, match_key matchfunc) : key_(key), cmp(matchfunc) { }
bool matched(const K& key) {
return cmp(key_, key);
}
private:
const K key_;
match_key cmp;
};
int main()
{
int i = 3;
int j = 4;
hashmap<int> hm(i, mymatcher);
cout << "i matches j? " << (hm.matched(j) ? "yes" : "no") << endl;
return 0;
}
#include <iostream>
using namespace std;
// TODO - replace this C construct with C++ equivalent
//typedef bool(*match_key)(const void* key1, const void* key2);
// somehow declare this as a typedef? need a way to declare a signature in C++
typedef template<class T>
using match_key = bool (*)(const T& key1, const T& key2);
// *** User defined matching function
bool mymatcher(const int i, const int j) {
return i == j;
}
template<class K>
class hashmap{
public:
hashmap(const K& key, match_key<K> matchfunc) : key_(key), cmp(matchfunc) { }
bool matched(const K& key) {
return cmp(key_, key);
}
private:
const K key_;
match_key<K> cmp;
};
int main()
{
int i = 3;
int j = 4;
hashmap<int> hm(i, mymatcher);
cout << "i matches j? " << (hm.matched(j) ? "yes" : "no") << endl;
return 0;
}
If the T of the match_key is supposed to be the same as the K of the hashmap, you can make the signature part of the hashmap:
template <typename T>
struct hashmap {
typedef bool (*match_key)(const T& key1, const T& key2);
....
}
...otherwise I would make the type of the comparator a second template parameter:
template <typename K, typename C>
struct hashmap {
C cmp;
hashmap(const K& key, C matchfunc) : key_(key), cmp(matchfunc) { }
...
}
this would give the user greater flexibility but also opens the door to long compiler errors.
The way passing a function as a pointer is very restrictive in C++. It won't be able to container any callable object in C++. To be specific, it will block the use of functor in C++.
Here functor, referred to any type T that satisfies:
which has overloaded calling operator;
Or
has user-defined conversion functions that enables it to be statically casted to a function pointer.
It either case, any object of such type is callable, and can be used as if they are names of functions.
An example to this is std::less, which is frequently used when using algorithms that need to compare 2 objects.
In order to be able to pass any callable object, you have to templaterize the type of the function:
template <class K, class Cmp = std::less<>>
class hashmap {
public:
hashmap<K>(const K& key, Cmp _cmp = {}): key_(key), cmp(_cmp) { }
bool matched(const K& key) {
return cmp(key_, key);
}
private:
const K key_;
Cmp cmp;
};
I have this code:
template<class T1, class T2>
class Pair
{
private:
T1 first;
T2 second;
public:
void SetFirst(T1 first)
{
this.first = first;
}
void SetSecond(T2 second)
{
this.second = second;
}
T1 GetFirst()
{
return first;
}
T2 GetSecond()
{
return second;
}
};
How could I implement two single methods SetValue() and GetValue(), instead of the four I have, that decides depending on parameters which generic type that should be used? For instance I'm thinking the GetValue() method could take an int parameter of either 1 or 2 and depending on the number, return either a variable of type T1 or T2. But I don't know the return type beforehand so is there anyway to solve this?
Not sure to understand what do you want and not exactly what you asked but...
I propose the use of a wrapper base class defined as follows
template <typename T>
class wrap
{
private:
T elem;
public:
void set (T const & t)
{ elem = t; }
T get () const
{ return elem; }
};
Now your class can be defined as
template <typename T1, typename T2>
struct Pair : wrap<T1>, wrap<T2>
{
template <typename T>
void set (T const & t)
{ wrap<T>::set(t); }
template <typename T>
T get () const
{ return wrap<T>::get(); }
};
or, if you can use C++11 and variadic templates and if you define a type traits getType to get the Nth type of a list,
template <std::size_t I, typename, typename ... Ts>
struct getType
{ using type = typename getType<I-1U, Ts...>::type; };
template <typename T, typename ... Ts>
struct getType<0U, T, Ts...>
{ using type = T; };
you can define Pair in a more flexible way as follows
template <typename ... Ts>
struct Pair : wrap<Ts>...
{
template <typename T>
void set (T const & t)
{ wrap<T>::set(t); }
template <std::size_t N, typename T>
void set (T const & t)
{ wrap<typename getType<N, Ts...>::type>::set(t); }
template <typename T>
T get () const
{ return wrap<T>::get(); }
template <std::size_t N>
typename getType<N, Ts...>::type get ()
{ return wrap<typename getType<N, Ts...>::type>::get(); }
};
Now the argument of set() can select the correct base class and the correct base element
Pair<int, long> p;
p.set(0); // set the int elem
p.set(1L); // set the long elem
otherwise, via index, you can write
p.set<0U>(3); // set the 1st (int) elem
p.set<1U>(4); // set the 2nd (long) elem
Unfortunately, the get() doesn't receive an argument, so the type have to be explicited (via type or via index)
p.get<int>(); // get the int elem value
p.get<long>(); // get the long elem value
p.get<0U>(); // get the 1st (int) elem value
p.get<1U>(); // get the 2nd (long) elem value
Obviously, this didn't work when T1 is equal to T2
The following is a (C++11) full working example
#include <iostream>
template <std::size_t I, typename, typename ... Ts>
struct getType
{ using type = typename getType<I-1U, Ts...>::type; };
template <typename T, typename ... Ts>
struct getType<0U, T, Ts...>
{ using type = T; };
template <typename T>
class wrap
{
private:
T elem;
public:
void set (T const & t)
{ elem = t; }
T get () const
{ return elem; }
};
template <typename ... Ts>
struct Pair : wrap<Ts>...
{
template <typename T>
void set (T const & t)
{ wrap<T>::set(t); }
template <std::size_t N, typename T>
void set (T const & t)
{ wrap<typename getType<N, Ts...>::type>::set(t); }
template <typename T>
T get () const
{ return wrap<T>::get(); }
template <std::size_t N>
typename getType<N, Ts...>::type get ()
{ return wrap<typename getType<N, Ts...>::type>::get(); }
};
int main()
{
//Pair<int, int> p; compilation error
Pair<int, long, long long> p;
p.set(0);
p.set(1L);
p.set(2LL);
std::cout << p.get<int>() << std::endl; // print 0
std::cout << p.get<long>() << std::endl; // print 1
std::cout << p.get<long long>() << std::endl; // print 2
p.set<0U>(3);
p.set<1U>(4);
p.set<2U>(5);
std::cout << p.get<0U>() << std::endl; // print 3
std::cout << p.get<1U>() << std::endl; // print 4
std::cout << p.get<2U>() << std::endl; // print 5
}
C++ is statically typed, so the argument given must be a template-argument instead a function-argument.
And while it will look like just one function each to the user, it's really two.
template <int i = 1> auto GetValue() -> std::enable_if_t<i == 1, T1> { return first; }
template <int i = 2> auto GetValue() -> std::enable_if_t<i == 2, T2> { return second; }
template <int i = 1> auto SetValue(T1 x) -> std::enable_if_t<i == 1> { first = x; }
template <int i = 2> auto SetValue(T2 x) -> std::enable_if_t<i == 2> { second = x; }
I use SFINAE on the return-type to remove the function from consideration unless the template-argument is right.
For this particular situation, you should definitely prefer std::pair or std::tuple.
You can simply overload SetValue() (provided T1 and T2 can be distinguished, if not you have a compile error):
void SetValue(T1 x)
{ first=x; }
void SetValue(T2 x)
{ second=x; }
Then, the compiler with find the best match for any call, i.e.
Pair<int,double> p;
p.SetValue(0); // sets p.first
p.SetValue(0.0); // sets p.second
With GetValue(), the information of which element you want to retrieve cannot be inferred from something like p.GetValue(), so you must provide it somehow. There are several options, such as
template<typename T>
std::enable_if_t<std::is_same<T,T1>,T>
GetValue() const
{ return first; }
template<typename T>
std::enable_if_t<std::is_same<T,T2>,T>
GetValue() const
{ return second; }
to be used like
auto a = p.GetValue<int>();
auto b = p.GetValue<double>();
but your initial version is good enough.
I am trying to create a templated wrapper class on stl unordered_map. I am passing the hash function class as a template parameter to the wrapper class and provided a string specialization. The below code compiles and works but if the commented part is included then compilation error saying:
"/usr/include/c++/6/bits/unordered_map.h:143:28: error: no matching
function for call to ‘HashFunction
::HashFunction()’
const hasher& __hf = hasher(),".
However, I am bound to have the ctor of the hash function class. I tried various ways but could not make it work. Please provide your thoughts/comments.
#include <iostream>
#include <unordered_map>
using namespace std;
template< class Key >
class HashFunction
{
public:
//HashFunction( const Key & inKey );
size_t operator()(const Key &inKey) const;
private:
unsigned mHashCode;
};
//template<>
//HashFunction< string >::HashFunction( const string & inKey )
//{
//mHashCode=std::hash<string>{}(inKey);
//}
template <>
size_t HashFunction< string >::operator()(const string &inKey) const
{
return std::hash<string>{}(inKey);
//return mHashCode;
}
template< class Key, class Val, class Hash = HashFunction< Key > >
class unordered_map_wrapper
{
public:
unordered_map_wrapper();
private:
unordered_map<Key, Val, Hash> * mTable;
};
template< class Key, class Val, class Hash >
unordered_map_wrapper< Key, Val, Hash >::unordered_map_wrapper()
{
mTable=new unordered_map<Key, Val, Hash>(10);
}
int main() {
unordered_map_wrapper<string, unsigned> h;
return 0;
}
This is not how the Hash template parameter is intended to work in std::unordered_map! The map creates one single Hash instance (using the default constructor, so you need to provide it!) which is used for all hash calculations needed further. So your class must look like this instead:
template<class Key>
class HashFunction
{
public:
// HashFunction(); <- can just leave it out...
size_t operator()(const Key& inKey) const;
};
template<>
size_t HashFunction<std::string>::operator()(const std::string& inKey) const
{
// calculate hash value in operator!!!
return std::hash<std::string>()(inKey);
}
To avoid constructing the std::hash all the time, though, I'd rather specialise the whole template class instead:
template<class Key>
class HashFunction; // leave entirely unimplemented
// (if it has no general meaning, at least...)
template<>
class HashFunction<std::string>
{
public:
size_t operator()(const std::string& inKey) const
{
return mHash(inKey);
}
private:
std::hash<std::string> mHash;
};
It does not make much sense re-implementing something that is already there, though. May I assume that you used std::string here just as a place holder for your own class?
By the way: A simple typedef would do the job easier than your wrapper class:
template <typename Key, typename Value>
using my_unordered_map = std::unordered_map<Key, Value, HashFunction<Key>>;
Maybe you are interested in alternatives, too? Lets first assume you have two classes (instead of std::string):
class C1
{ };
class C2
{ };
Most elegant solution (in my eyes at least) is simply specialising std::hash for your classes (while in general, it is illegal to add something to std namespace, template specialisations are the exception...):
namespace std
{
template<>
class hash<C1>
{
public:
size_t operator()(C const& c) const
{
return 0; // your implementation here...
}
};
// same for C2
}
// no typedef necessary, just use std::unordered_map directly:
std::unordered_map<C1, unsigned> m1;
std::unordered_map<C2, unsigned> m2;
You can provide your own HashFunction class, providing overloads:
class HashFunction
{
public:
size_t operator()(C1 const& c) const
{
return 0;
}
size_t operator()(C2 const& c) const
{
return 0;
}
};
Again, a typedef makes your life easier:
template <typename Key, typename Value>
using my_unordered_map = std::unordered_map<Key, Value, HashFunction>;
std::unordered_map<C1, unsigned, HashFunction> m1;
my_unordered_map<C1, unsigned> m1_;
std::unordered_map<C2, unsigned, HashFunction> m2;
my_unordered_map<C2, unsigned> m2_;
Finally, if you absolutely need to initialise your HashFunction with some parameters to configure it correctly, you can do so, but you have to deliver a pre-configured instance to your hash map then!
template<typename T>
class HashFunction
{
public:
HashFunction(double value);
size_t operator()(T const& c) const;
private:
double data;
};
template<typename T>
HashFunction<T>::HashFunction(double value)
: data(value)
{ }
template<>
size_t HashFunction<C1>::operator()(C1 const& c) const
{
return static_cast<size_t>(data);
};
template<>
size_t HashFunction<C2>::operator()(C2 const& c) const
{
return static_cast<size_t>(data);
};
template <typename Key, typename Value>
using my_unordered_map = std::unordered_map<Key, Value, HashFunction<Key>>;
my_unordered_map<C1, unsigned> m1(12, HashFunction<C1>(10.12));
my_unordered_map<C2, unsigned> m2(10, HashFunction<C2>(12.10));
Well, now, at least, your wrapper class can come in handy again:
template <typename Key, typename Value, typename Hash = HashFunction<Key>>
class unordered_map_wrapper
{
public:
unordered_map_wrapper()
: mMap(16, Hash())
{ }
unordered_map_wrapper(double parameter)
: mMap(16, Hash(parameter))
{ }
private:
std::unordered_map<Key, Value, Hash> mMap;
};
unordered_map_wrapper<C1, unsigned> m1(10.12);
unordered_map_wrapper<C2, unsigned> m2(12.10);
// possible due to provided default ctor:
unordered_map_wrapper<std::string, unsigned, std::hash<std::string>> m3;
It expects to have a default constructor, which is removed when you define your custom version.
This compiles:
template< class Key >
class HashFunction
{
public:
HashFunction(){};
HashFunction( const Key & inKey );
size_t operator()(const Key &inKey) const;
private:
unsigned mHashCode;
};
I have these two functors:
template<typename T>
struct identity {
const T &operator()(const T &x) const {
return x;
}
};
template<typename KeyFunction>
class key_helper {
public:
key_helper(const KeyFunction& get_key_) : get_key(get_key_) { }
template<typename T, typename K>
const K operator()(const T& x, const int& n) {
return get_key(x);
}
private:
KeyFunction get_key;
};
However, if i use the second functor in a templated function. I got errors:
template<typename T, typename K>
void test(T item, K key) {
identity<T> id;
key_helper<identity<T> > k(id);
K key2 = k(item, 2); // compiler cannot deduce type of K
key2 = k.operator()<T, K>(item, 2); // expected primary-expression before ',' token
}
How can i call the functor's operator() from the test function?
It can't deduce the return type of operator(), K, in any way, so you need to explicitly specify the template arguments. The reason your second attempt doesn't work is because you need to include the template keyword:
K key2 = k.template operator()<T,K>(item, 2);
I am a newer for C++, and my first language is Chinese, so my words with English may be unmeaningful, say sorry first.
I know there is a way to write a function with variable parameters which number or type maybe different each calling, we can use the macros of va_list,va_start and va_end. But as everyone know, it is the C style. When we use the macros, we will lose the benefit of type-safe and auto-inference, then I try do it whit C++ template. My work is followed:
#include<iostream>
#include<vector>
#include<boost/any.hpp>
struct Argument
{
typedef boost::bad_any_cast bad_cast;
template<typename Type>
Argument& operator,(const Type& v)
{
boost::any a(v);
_args.push_back(a);
return *this;
}
size_t size() const
{
return _args.size();
}
template<typename Type>
Type value(size_t n) const
{
return boost::any_cast<Type>(_args[n]);
}
template<typename Type>
const Type* piont(size_t n) const
{
return boost::any_cast<Type>(&_args[n]);
}
private:
std::vector<boost::any> _args;
};
int sum(const Argument& arg)
{
int sum=0;
for(size_t s=0; s<arg.size(); ++s)
{
sum += arg.value<int>(s);
}
return sum;
}
int main()
{
std::cout << sum((Argument(), 1, 3, 4, 5)) << std::endl;
return 0;
}
I think it's ugly, I want to there is a way to do better? Thanks, and sorry for language errors.
You can do something like this:
template <typename T>
class sum{
T value;
public:
sum ()
: value() {};
// Add one argument
sum<T>& operator<<(T const& x)
{ value += x; return *this; }
// to get funal value
operator T()
{ return value;}
// need another type that's handled differently? Sure!
sum<T>& operator<<(double const& x)
{ value += 100*int(x); return *this; }
};
#include <iostream>
int main()
{
std::cout << (sum<int>() << 5 << 1 << 1.5 << 19) << "\n";
return 0;
}
Such technique (operator overloading and stream-like function class) may solve different problems with variable arguments, not only this one. For example:
create_window() << window::caption - "Hey" << window::width - 5;
// height of the window and its other parameters are not set here and use default values
After giving it some thought, I found a way to do it using a typelist. You don't need an any type that way, and your code becomes type-safe.
It's based on building a template structure containing a head (of a known type) and a tail, which is again a typelist. I added some syntactic sugar to make it more intuitive: use like this:
// the 1 argument processing function
template< typename TArg > void processArg( const TArg& arg ) {
std::cout << "processing " << arg.value << std::endl;
}
// recursive function: processes
// the first argument, and calls itself again for
// the rest of the typelist
// (note: can be generalized to take _any_ function
template< typename TArgs >
void process( const TArgs& args ) {
processArg( args.head );
return process( args.rest );
}
template<> void process<VoidArg>( const VoidArg& arg ){}
int main() {
const char* p = "another string";
process( (arglist= 1, 1.2, "a string", p ) );
}
And here is the argument passing framework:
#include <iostream>
// wrapper to abstract away the difference between pointer types and value types.
template< typename T > struct TCont {
T value;
TCont( const T& t ):value(t){}
};
template<typename T, size_t N> struct TCont< T[N] > {
const T* value;
TCont( const T* const t ) : value( t ) { }
};
template<typename T> struct TCont<T*> {
const T* value;
TCont( const T* t ): value(t){}
};
// forward definition of type argument list
template< typename aT, typename aRest >
struct TArgList ;
// this structure is the starting point
// of the type safe variadic argument list
struct VoidArg {
template< typename A >
struct Append {
typedef TArgList< A, VoidArg > result;
};
template< typename A >
typename Append<A>::result append( const A& a ) const {
Append<A>::result ret( a, *this );
return ret;
}
//syntactic sugar
template< typename A > typename Append<A>::result operator=( const A& a ) const { return append(a); }
} const arglist;
// typelist containing an argument
// and the rest of the arguments (again a typelist)
//
template< typename aT, typename aRest >
struct TArgList {
typedef aT T;
typedef aRest Rest;
typedef TArgList< aT, aRest > Self;
TArgList( const TCont<T>& head, const Rest& rest ): head( head ), rest( rest ){}
TCont<T> head;
Rest rest;
template< typename A > struct Append {
typedef TArgList< T, typename Rest::Append<A>::result > result;
};
template< typename A >
typename Append< A >::result append( const A& a ) const {
Append< A >::result ret ( head.value, (rest.append( a ) ) );
return ret;
}
template< typename A > typename Append<A>::result operator,( const A& a ) const { return append(a); }
};