Syntax to pass argument to unordered_set hash function in c++ - c++

I have created a hasher class for a custom type I'm using, but it has a constructor that takes an argument. I can't figure out the syntax to use this in an unordered_set.
class Hasher {
unsigned arg;
public:
Hasher(unsigned a) : arg(a) {}
size_t operator()(const MyType& t) const {
return calculate_hash(arg, t);
}
}
int main() {
unordered_set<MyType, Hasher(2)> myset; // compilation error
}
The error message:
In file included from Tetrahedron.cc:5:
./Triangulation.h:52:29: error: template argument for template type parameter must be a type
unordered_set<TetraFace,FaceHasher(2)> faces2;
^~~~~~~~~~~~~
/bin/../lib/gcc/x86_64-redhat-linux/6.3.1/../../../../include/c++/6.3.1/bits/unordered_set.h:90:11: note: template parameter is declared here
class _Hash = hash<_Value>,
^
I also tried
unordered_set<MyType, Hasher> myset(Hasher(2));
but I still get an error:
In file included from Tetrahedron.cc:5:
./Triangulation.h:52:59: error: expected ')'
unordered_set<TetraFace,FaceHasher> faces2(FaceHasher(2));
^
./Triangulation.h:52:58: note: to match this '('
unordered_set<TetraFace,FaceHasher> faces2(FaceHasher(2));
^

You're getting a compile error there because you're trying to pass an object (i.e. instance) of type Hasher as a template argument.
Like your error describes: template argument for template type parameter must be a type
It's expecting a type, and you're passing in a value.
Parameterize the arg at the type level.
template<unsigned A>
class Hasher {
unsigned arg = A;
public:
size_t operator()(const int& t) const {
std::cout << arg << std::endl;
return 0;
}
};
int main() {
std::unordered_set<int, Hasher<2>> myset;
myset.insert(5); // prints 2
std::unordered_set<int, Hasher<3>> myset2;
myset2.insert(3); // prints 3
}

Unfortunately it is not possible to construct a std::unorderd_set with just the hash object. All of the constructors that take the hash object have a parameter before it for bucket_count. You would need to specify the value for it like
unordered_set<MyType, Hasher> myset(some_bucket_count_value, Hasher(2));
If you do not want to do that then you have to make Hasher default constructable.
Also not that
return calculate_hash(arg);
Is not going to work as you will always hash arg no matter what MyType you pass. You need to be hashing the MyType object for the std::unordered_set to really work.

Related

"Cannot form reference to void" error even with `requires(!std::is_void_v<T>)`

I'm writing a pointer class and overloading the dereference operator operator*, which returns a reference to the pointed-to object. When the pointed-to type is not void this is fine, but we cannot create a reference to void, so I'm trying to disable the operator* using a requires clause when the pointed-to type is void.
However, I'm still getting compiler errors from GCC, Clang, and MSVC for the void case even though it does not satisfy the requires clause.
Here is a minimal example and compiler explorer link (https://godbolt.org/z/xbo5v3d1E).
#include <iostream>
#include <type_traits>
template <class T>
struct MyPtr {
T* p;
T& operator*() requires(!std::is_void_v<T>)
{
return *p;
}
};
int main() {
int x = 42;
MyPtr<int> i_ptr{&x};
*i_ptr = 41;
MyPtr<void> v_ptr{&x};
std::cout << *static_cast<int*>(v_ptr.p) << '\n';
std::cout << x << '\n';
return 0;
}
And here is the error (in Clang):
<source>:7:6: error: cannot form a reference to 'void'
T& operator*()
^
<source>:20:17: note: in instantiation of template class 'MyPtr<void>' requested here
MyPtr<void> v_ptr{&x};
^
1 error generated.
ASM generation compiler returned: 1
<source>:7:6: error: cannot form a reference to 'void'
T& operator*()
^
<source>:20:17: note: in instantiation of template class 'MyPtr<void>' requested here
MyPtr<void> v_ptr{&x};
^
1 error generated.
Execution build compiler returned: 1
However, if I change the return type of operator* from T& to auto&, then it works in all 3 compilers. If I use trailing return type auto ... -> T& I also get errors in all 3 compilers.
Is this a triple compiler bug, user error, or is this intended behavior?
The requires clause doesn't matter because T is a parameter of the class template. Once T is known, the class can be instantiated, but if T is void, that instantiation fails because of the member function signature.
You can either put that requires on the entire class, or make the member function a template like this:
template<typename U = T>
U& operator*() requires(!std::is_void_v<U> && std::is_same_v<T, U>)
{
return *p;
}
Demo
Making the return type auto& is almost the same thing: the return type is deduced by replacing auto with an imaginary type template parameter U and then performing template argument deduction. Note that the version above with requires makes the compilation error clear if you try to use this function with U=void: GCC says template argument deduction/substitution failed: constraints not satisfied.
I don't think there is a way to reproduce exactly what an auto& return type does by making the function a template. Something like this might come close:
template<typename U = T>
std::enable_if_t<!std::is_void_v<T>, U>& operator*()
{
return *p;
}
Compare what you're trying with the equivalent using std::enable_if (without concepts):
template<std::enable_if_t<!std::is_void_v<T>, bool> = true>
T& operator*()
{
return *p;
}
This will give you an error like no type named 'type' in 'struct std::enable_if<false, bool>', because SFINAE wouldn't work in this situation where T is not a parameter of the function template.
Technically, you can also change the return type depending on whether T is void, but this is probably a bad idea:
using R = std::conditional_t<std::is_void_v<T>, int, T>;
R& operator*()
{
// calling this with T=void will fail to compile
// 'void*' is not a pointer-to-object type
return *p;
}
In addition to the Nelfeal's answer, let me give an alternative solution. The problem is not in the dependence of requires condition on T, but is in the return type T&. Let's use a helper type trait:
std::add_lvalue_reference_t<T> operator*()
requires(!std::is_void_v<T>)
{
...
}
It works because std::add_lvalue_reference_t<void> = void, which makes operator*() signature valid for T = void.

Error when inheriting from templated class and calling templated function

I've got some template code that I'm modifying and I've run into an odd error that I can't work around. I was able to recreate the problem with the below simpler (but admittedly pointless) code snippet:
struct Widget
{
};
template <typename A>
class Foo
{
public:
template <int numA>
inline bool funcCall()
{
return numA > 0;
}
inline bool funcCallNoTemplate()
{
return false;
}
};
template <typename B>
class Bar : public Foo<B>
{
public:
// doesn't work
bool concrete()
{
return Foo<B>::funcCall<5>();
}
// works fine
bool other()
{
return Foo<B>::funcCallNoTemplate();
}
};
int main()
{
Bar<Widget> b;
b.concrete();
b.other();
return 0;
}
The error I get with GCC 4.7 is the following (line 30 is the body of Bar::concrete):
example.cxx: In member function ‘bool Bar<B>::concrete()’:
example.cxx:30: error: expected primary-expression before ‘)’ token
example.cxx: In member function ‘bool Bar<B>::concrete() [with B = Widget]’:
example.cxx:43: instantiated from here
example.cxx:30: error: invalid operands of types ‘<unresolved overloaded function type>’ and ‘int’ to binary ‘operator<’
It seems like the compiler can't even parse this correctly, am I missing something here that makes that line completely bogus?
It seems like the compiler can't even parse this correctly, am I missing something here that makes that line completely bogus?
Yes. You need to use the template disambiguator:
return Foo<B>::template funcCall<5>();
// ^^^^^^^^
This way you will tell the compiler to parse the dependent name funcCall as the name of a member function template, and the subsequent angular brackets as delimiters for the corresponding template arguments.
Without it, funcCall will be parsed as the name of a data member, while < and > will be parsed as less-than and greater-than, respectively.

How to pass array to function template with reference

I am learning c++ template concepts. I do not understand the following.
#include <iostream>
#include <typeinfo>
using namespace std;
template <typename T>
T fun(T& x)
{
cout <<" X is "<<x;
cout <<"Type id is "<<typeid(x).name()<<endl;
}
int main ( int argc, char ** argv)
{
int a[100];
fun (a);
}
What i am trying?
1) T fun (T & x)
Here x is a reference, and hence will not decayed 'a' into pointer type,
but while compiling , i am getting the following error.
error: no matching function for call to ‘fun(int [100])’
When I try non-reference, it works fine. As I understand it the array is decayed into pointer type.
C-style arrays are very basic constructs which are not assignable, copyable or referenceable in the way built-ins or user defined types are. To achieve the equivalent of passing an array by reference, you need the following syntax:
// non-const version
template <typename T, size_t N>
void fun( T (&x)[N] ) { ... }
// const version
template <typename T, size_t N>
void fun( const T (&x)[N] ) { ... }
Note that here the size of the array is also a template parameter to allow the function to work will all array sizes, since T[M] and T[N] are not the same type for different M, N. Also note that the function returns void. There is no way of returning an array by value, since the array is not copyable, as already mentioned.
The problem is in the return type: you cannot return an array because arrays are non-copiable. And by the way, you are returning nothing!
Try instead:
template <typename T>
void fun(T& x) // <--- note the void
{
cout <<" X is "<<x;
cout <<"Type id is "<<typeid(x).name()<<endl;
}
And it will work as expected.
NOTE: the original full error message (with gcc 4.8) is actually:
test.cpp: In function ‘int main(int, char**)’:
test.cpp:17:10: error: no matching function for call to ‘fun(int [100])’
fun (a);
^
test.cpp:17:10: note: candidate is:
test.cpp:7:3: note: template<class T> T fun(T&)
T fun(T& x)
^
test.cpp:7:3: note: template argument deduction/substitution failed:
test.cpp: In substitution of ‘template<class T> T fun(T&) [with T = int [100]]’:
test.cpp:17:10: required from here
test.cpp:7:3: error: function returning an array
The most relevant line is the last one.

g++ compiler error: couldn't deduce template parameter ‘_Funct’

I'm trying to use an ANSI C++ for_each statement to iterate over and print the elements of a standard vector. It works if I have the for_each call a non-overloaded function, but yields a compiler error if I have it call an overloaded function.
Here's a minimal test program to show where the compiler error occurs:
#include <algorithm>
#include <iostream>
#include <vector>
struct S {
char c;
int i;
};
std::vector<S> v;
void print_struct(int idx);
void print_struct(const struct S& s);
// f: a non-overloaded version of the preceding function.
void f(const struct S& s);
int main()
{
v.push_back((struct S){'a', 1});
v.push_back((struct S){'b', 2});
v.push_back((struct S){'c', 3});
for (unsigned int i = 0; i < v.size(); ++i)
print_struct(i);
/* ERROR! */
std::for_each(v.begin(), v.end(), print_struct);
/* WORKAROUND: */
std::for_each(v.begin(), v.end(), f);
return 0;
}
// print_struct: Print a struct by its index in vector v.
void print_struct(int idx)
{
std::cout << v[idx].c << ',' << v[idx].i << '\n';
}
// print_struct: Print a struct by reference.
void print_struct(const struct S& s)
{
std::cout << s.c << ',' << s.i << '\n';
}
// f: a non-overloaded version of the preceding function.
void f(const struct S& s)
{
std::cout << s.c << ',' << s.i << '\n';
}
I compiled this in openSUSE 12.2 using:
g++-4.7 -ansi -Wall for_each.cpp -o for_each
The full error message is:
for_each.cpp: In function ‘int main()’:
for_each.cpp:31:48: error: no matching function for call to ‘for_each(std::vector<S>::iterator, std::vector<S>::iterator, <unresolved overloaded function type>)’
for_each.cpp:31:48: note: candidate is:
In file included from /usr/include/c++/4.7/algorithm:63:0,
from for_each.cpp:5:
/usr/include/c++/4.7/bits/stl_algo.h:4436:5: note: template<class _IIter, class _Funct> _Funct std::for_each(_IIter, _IIter, _Funct)
/usr/include/c++/4.7/bits/stl_algo.h:4436:5: note: template argument deduction/substitution failed:
for_each.cpp:31:48: note: couldn't deduce template parameter ‘_Funct’
I don't see any search results for this particular error on Stack Overflow, or on the web generally. Any help would be appreciated.
A names refers to an overload set. You'll need to specify which overload you want:
std::for_each(v.begin(), v.end(), (void (&)(S const&)) print_struct);
Another approach is to use a polymorphic callable function object as a helper:
struct PrintStruct
{
template <typename T> void operator()(T const& v) const
{ return print_struct(v); }
};
int main()
{
PrintStruct helper;
std::vector<S> sv;
std::vector<int> iv;
// helper works for both:
std::for_each(sv.begin(), sv.end(), helper);
std::for_each(iv.begin(), iv.end(), helper);
std::for_each declaration looks like this:
template<class InputIter, class Func>
void for_each(InputIter first, InputIter last, Func func);
As you can see, it takes anything you give it as the third parameter. There is no restriction that it has to be a callable type of a certain signature or a callable type at all.
When dealing with overloaded functions, they're inherently ambiguous unless you give them some context to select the right one. In a call to an overloaded function, this context are the arguments you pass. When you need a pointer, however, you can't use arguments as a context, and the for_each parameter also doesn't count as a context, since it takes anything.
As an example of where a function parameter can be a valid context to select the right overload, see this:
// our overloads
void f(int){}
void f(double){}
typedef void (*funcptr_type)(int);
void g(funcptr_type){}
// ...
g(&f); // will select 'void f(int)' overload, since that's
// the only valid one given 'g's parameter
As you can see, you give a clear context here that helps the compiler select the right overload and not have it ambiguous. std::for_each's parameters do not give such a context, since they take anything.
There are two solutions:
manually provide the context either by
casting to the right function pointer type, or
using an intermediate variable of the right type and passing that
use a non-overloaded function that dispatches to an overloaded one (as you did with f)
Note that in C++11, you could also use a lambda for the second option:
std::for_each(v.begin(), v.end(), [](const S& s){ print_struct(s); });
Some notes on your code:
(struct S){'a', 1} is a compound literal and not standard C++
you don't need struct S in C++, only S suffices

Invalid Template Error passing class function using Boost

Trying to using a template, where the argument is
template<class T, boost::function<long (T*)> &f>
static long myFunc(const vector<boost::shared_ptr<T>> &inputVector)
{ // do stuff}
This is the call I make
long i = myFunc<MyClass, boost::bind(&MyClass::myClassFunc, _1)>(myInputVector);
where the signature of the function is
long myClassFunc() const { return m_value; }
Getting the following compiler error:
error C2975: 'f' : invalid template argument for 'myFunc', expected compile-time constant expression
What do I need to get this to compile?
Binding arguments to a function is a run-time operation. When you pass a value as a template parameter, the value has to be known at compile time. Pass the boost::function as an argument.
template<class T>
static long myFunc(const vector<boost::shared_ptr<T>> &inputVector, boost::function<long (T*)> &f)
{ // do stuff
}
call it like that:
long i = myFunc<MyClass)>(myInputVector, boost::bind(&MyClass::myClassFunc, _1));