I have a template class with two template arguments with the following constructor and member:
template <class T, class TCompare>
class MyClass {
...
public:
MyClass(TCompare compare);
void addElement(T newElement);
...
};
And I have a structure which overloads operator () for integer comparison:
struct IntegerLess {
bool operator () {const int& a, const int& b) {
if (a < b)
return true;
return false;
}
};
I create an object of class 'MyClass' and try to use it:
MyClass<int, IntegerLess> myClassObject(IntegerLess());
myClassObject.addElement(10);
However, I got the following compile-time error:
error: request for member ‘addElement’ in ‘myClassObject’, which is of non-class type ‘MyClass<int, IntegerLess>(IntegerLess (*)())’
How can I correct it? Thanks!
This is the most vexing parse. You can fix the problem by throwing in an extra set of parentheses:
MyClass<int, IntegerLess> myClassObject((IntegerLess()));
// ^ ^
Note that if you had passed an lvalue directly, there would have been no scope for this parse:
IntegerLess x;
MyClass<int, IntegerLess> myClassObject(x);
Declare the IntegerLess object separately:
IntegerLess comparator;
MyClass<int, IntegerLess> myClassObject(comparator);
myClassObject.addElement(10);
Alternatively, add parentheses like juanchopanza suggested.
Related
I'm trying to call a function from within a template function inside a template.
The call itself, however, doesn't compile, instead I get the following error:
/home/alexis/tmp/b.cpp: In instantiation of ‘bool callback_manager<C>::call_member(F, ARGS ...) [with F = bool (main()::foo::*)(int, int, int); ARGS = {int, int, int}; C = std::vector<std::shared_ptr<main()::foo> >]’:
/home/alexis/tmp/b.cpp:43:47: required from here
/home/alexis/tmp/b.cpp:15:19: error: no match for ‘operator->*’ (operand types are ‘std::shared_ptr<main()::foo>’ and ‘bool (main()::foo::*)(int, int, int)’)
if(!(c->*func)(&args...))
~~^~~~~~~~
Here is a simplified version of the code I'm trying to compile:
#include <memory>
#include <vector>
template<typename C>
class callback_manager
{
public:
template<typename F, typename ... ARGS>
bool call_member(F func, ARGS ... args)
{
C callbacks(f_callbacks);
for(auto c : callbacks)
{
if(!(c->*func)(args...))
{
return false;
}
}
return true;
}
private:
C f_callbacks;
};
int main()
{
class foo
{
public:
typedef std::shared_ptr<foo> pointer_t;
typedef std::vector<pointer_t> vector_t;
bool the_callback(int, int, int)
{
return true;
}
};
callback_manager<foo::vector_t> m;
m.call_member(&foo::the_callback, 5, 13, 7);
return 1;
}
Looking at the parameters, it seems to be that both are correct:
std::shared_ptr<main()::foo>
and
bool (main()::foo::*)(int, int, int)
The fact is that the ->* operator doesn't work with the std::shared_ptr<>.
The solution is to retrieve the bare pointer like so:
if(!(c.get()->*func)(args...)) ...
It then compiles as expected.
You can also rewrite it as follow, which I think is more cryptic:
if(!(*c).*func)(args...)) ...
(i.e. the shared_ptr::operator * () function returns the pointed to object held by the shared pointer, hence the .* operator is used in this case.)
Replace
if(!(c->*func)(args...))
with
if(!(std::cref(func)(c, args...)))
to use the INVOKE machinery of C++. Or use std::invoke directly.
INVOKE concept in the standard, and std::invoke, where designed to work with pmfs and smart pointers.
Meanwhile, ->* isn't overloaded by smart pointers. So direct use like that won't work.
As a side benefit, now a non member function can be passed in as the func.
I've observed I cannot do &decltype(c)::f to get a pointer to member function f using a class instance c, but I can do &C::f to get that pointer to member function, using the class type C, which I believe is the same as decltype(c).
See this minimal example:
struct C{
int f()
{
return 5;
}
} c;
template<typename T, T t, typename S, S*s> void callCf()
{
(s->*t)();
}
int main()
{
callCf<decltype(&decltype(c)::f),&decltype(c)::f,C,&c>();
}
Compiling this gives:
In function 'int main()':
15:3: error: parse error in template argument list
15:58: error: no matching function for call to 'callCf()'
15:58: note: candidate is:
8:49: note: template<class T, T t, class S, S* s> void callCf()
8:49: note: template argument deduction/substitution failed:
15:58: error: template argument 2 is invalid
Using the following works as expected:
int main()
{
callCf<decltype(&decltype(c)::f),&C::f,C,&c>();
}
Even this works:
int main()
{
using tC = decltype(c);
callCf<decltype(&decltype(c)::f),&tC::f,C,&c>();
}
This also works:
template<typename T>
struct forward_type{
typedef T type;
};
int main()
{
callCf<decltype(&decltype(c)::f),&forward_type<decltype(c)>::type::f,C,&c>();
}
My question is: why is it not possible to use decltype to obtain a pointer to member function like this &decltype(c)::f?
Edit: #Paul Sanders has shown in the comments that the minimal example works in c++17. I'm still using c++14. Does c++17 include some changes to the language that allow my minimal example to compile?
c is an lvalue, so decltype(c) will not return the C type itself, which is why decltype(c)::f does not work. decltype(c) will actually return a C& reference type instead:
If the argument is any other expression of type T, and
...
b) if the value category of expression is lvalue, then decltype yields T&;
...
You can use std::remove_reference/_t to get the C type from C&, eg:
int main()
{
callCf<
decltype(&std::remove_reference_t<decltype(c)>::f),
&std::remove_reference_t<decltype(c)>::f,
std::remove_reference_t<decltype(c)>,
&c
>();
}
Live Demo
Which can then be simplified with a using statement:
int main()
{
using tC = std::remove_reference_t<decltype(c)>;
callCf<decltype(&tC::f), &tC::f, tC, &c>();
}
Live Demo
The following code compiles perfectly if:
I don't include <iostream> or
I name operator== as alp::operator==.
I suppose there is a problem with <iostream> and operator==, but I don't know what.
I compile the code with gcc 7.3.0, clang++-6.0 and goldbolt. Always the same error.
The problem is that the compiler is trying to cast the parameters of operator== to const_iterator, but why? (I suppose the compiler doesn't see my version of operator==, and looks for other versions).
#include <vector>
#include <iostream> // comment and compile
namespace alp{
template <typename It_base>
struct Iterator {
using const_iterator = Iterator<typename It_base::const_iterator>;
operator const_iterator() { return const_iterator{}; }
};
template <typename It_base>
bool operator==(const Iterator<It_base>& x, const Iterator<It_base>& y)
{ return true;}
}// namespace
struct Func{
int& operator()(int& p) const {return p;}
};
template <typename It, typename View>
struct View_iterator_base{
using return_type = decltype(View{}(*It{}));
using const_iterator =
View_iterator_base<std::vector<int>::const_iterator, Func>;
};
using view_it =
alp::Iterator<View_iterator_base<std::vector<int>::iterator, Func>>;
int main()
{
view_it p{};
view_it z{};
bool x = operator==(z, p); // only compiles if you remove <iostream>
bool y = alp::operator==(z,p); // always compile
}
Error message:
yy.cpp: In instantiation of ‘struct View_iterator_base<__gnu_cxx::__normal_iterator<const int*, std::vector<int> >, Func>’:
yy.cpp:9:73: required from ‘struct alp::Iterator<View_iterator_base<__gnu_cxx::__normal_iterator<const int*, std::vector<int> >, Func> >’
yy.cpp:44:29: required from here
yy.cpp:28:42: error: no match for call to ‘(Func) (const int&)’
using return_type = decltype(View{}(*It{}));
~~~~~~^~~~~~~
yy.cpp:22:10: note: candidate: int& Func::operator()(int&) const <near match>
int& operator()(int& p) const {return p;}
^~~~~~~~
yy.cpp:22:10: note: conversion of argument 1 would be ill-formed:
yy.cpp:28:42: error: binding reference of type ‘int&’ to ‘const int’ discards qualifiers
using return_type = decltype(View{}(*It{}));
~~~~~~^~~~~~~
I've made a more minimal test case here: https://godbolt.org/z/QQonMG .
The relevant details are:
A using type alias does not instantiate a template. So for example:
template<bool b>
struct fail_if_true {
static_assert(!b, "template parameter must be false");
};
using fail_if_used = fail_if_true<true>;
will not cause a compile time error (if fail_if_used isn't used)
ADL also inspects template parameter classes. In this case, std::vector<int>::iterator is __gnu_cxx::__normal_iterator<const int*, std::vector<int> >, Func>, which has a std::vector<int> in it's template. So, operator== will check in the global namespace (always), alp (As alp::Iterator is in alp), __gnu_cxx and std.
Your View_iterator_base::const_iterator is invalid. View_iterator_base::const_interator::result_type is defined as decltype(Func{}(*std::vector<int>::const_iterator{})). std::vector<int>::const_iterator{} will be a vectors const iterator, so *std::vector<int>::const_iterator{} is a const int&. Func::operator() takes an int&, so this means that the expression is invalid. But it won't cause a compile time error if not used, for the reasons stated above. This means that your conversion operator is to an invalid type.
Since you don't define it as explicit, the conversion operator (To an invalid type) will be used to try and match it to the function parameters if they don't already match. Obviously this will finally instantiate the invalid type, so it will throw a compile time error.
My guess is that iostream includes string, which defines std::operator== for strings.
Here's an example without the std namespace: https://godbolt.org/z/-wlAmv
// Avoid including headers for testing without std::
template<class T> struct is_const { static constexpr const bool value = false; } template<class T> struct is_const<const T> { static constexpr const bool value = true; }
namespace with_another_equals {
struct T {};
bool operator==(const T&, const T&) {
return true;
}
}
namespace ns {
template<class T>
struct wrapper {
using invalid_wrapper = wrapper<typename T::invalid>;
operator invalid_wrapper() {}
};
template<class T>
bool operator==(const wrapper<T>&, const wrapper<T>&) {
return true;
}
}
template<class T>
struct with_invalid {
static_assert(!is_const<T>::value, "Invalid if const");
using invalid = with_invalid<const T>;
};
template<class T>
void test() {
using wrapped = ns::wrapper<with_invalid<T>>;
wrapped a;
wrapped b;
bool x = operator==(a, b);
bool y = ns::operator==(a, b);
}
template void test<int*>();
// Will compile if this line is commented out
template void test<with_another_equals::T>();
Note that just declaring operator const_iterator() should instantiate the type. But it doesn't because it is within templates. My guess is that it is optimised out (where it does compile because it's unused) before it can be checked to show that it can't compile (It doesn't even warn with -Wall -pedantic that it doesn't have a return statement in my example).
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.
all. I am trying to learn something about template inherit. I want to cast a temp derived object to its base reference. But I come across this problem:
typedef long size64_t;
//////Base class
template <typename _Scalar>
class MatrixBase{
public:
virtual _Scalar operator()(size64_t rowid, size64_t colid) = 0;
};
//////Derived class 1
template <typename _Scalar>
class MatrixHolder : public MatrixBase<_Scalar>{
public:
MatrixHolder(){};
inline _Scalar operator()(size64_t rowid, size64_t colid){return 0;}
};
//////Derived class 2
template <typename _Scalar>
class Matrix : public MatrixBase<_Scalar>{
public:
Matrix(){};
inline _Scalar operator()(size64_t rowid, size64_t colid){return 0;}
};
//////The function with parameters as Base class reference, wanting to get derived object as input.
template <typename _Scalar>
MatrixHolder<_Scalar> apply(MatrixBase<_Scalar>& lhs, MatrixBase<_Scalar>& rhs){
MatrixHolder<_Scalar> result;
return result;
}
and in main, we have:
void main(){
Matrix<double> m1;
Matrix<double> m2;
apply(m1, m2);//Sucess
apply(m1, apply(m1, m2));//Fail
}
the compiler said:
note: candidate function [with _Scalar = double] not viable: no known conversion from
'MatrixHolder<double>' to 'MatrixBase<double> &' for 2nd argument
MatrixHolder<_Scalar> apply(MatrixBase<_Scalar>& lhs, MatrixBase<_Scalar>& rhs){
^
1 error generated.
apply(m1, apply(m1, m2));//Fail
The problem here is that the inner apply returns a temporary, which cannot bind to the non-const reference parameter of the outer apply.
If you can make the parameters MatrixBase<_Scalar> const& it would be a possible match.