c++ compile error with template when using self-defined "bind3rd" function - c++

I want to write a function like "bind1st, bind2nd" to support multifields sort by using stl sort. Can't using std:bind since my g++ version is 3.4.5
It is called like this:
#include <alogritm>
std::sort(begin(), end(), bind3rd(SortCond(), indicate));
My template function is:
#ifndef __INCLUDE_TRIPLE_FUNCTION_H_
#define __INCLUDE_TRIPLE_FUNCTION_H_
#define TRIPLE_ARG(Operation, Type) Operation::Type
// Define the triple_function prototype
template<class Arg1, class Arg2, class Arg3, class Result>
struct triple_function
{
// Define the argument type alias
typedef Arg1 first_argument_type;
typedef Arg2 second_argument_type;
typedef Arg3 third_argument_type;
typedef Result result_type;
};
template <class Operation>
class binder3rd : public binary_function<typename TRIPLE_ARG(Operation, first_argument_type),
typename TRIPLE_ARG(Operation, second_argument_type), typename TRIPLE_ARG(Operation, result_type)>
{
protected:
Operation m_op;
typename Operation::third_argument_type value;
public:
binder3rd(const Operation& x, const typename Operation::third_argument_type y):m_op(x), value(y){}
// Convert this function to binary_function using the third argment
typename Operation::result_type operator()(const typename Operation::first_argument_type& x, const typename Operation::second_argument_type& y) const
{
return m_op(x, y, value);
}
};
// bind3rd function implementation
template<class Operation, class Arg>
inline binder3rd<Operation> bind3rd(const Operation& fn, const Arg& x)
{
return binder3rd<Operation>(fn, x);
}
#endif //__INCLUDE/TRIPLE_FUNCTION_H_
/* vim: set expandtab ts=4 sw=4 sts=4 tw=100: */
And My test cpp file is:
#include <algorithm>
#include <cstdlib>
#include "triple_function.h"
using namespace std;
class TestClass{
public:
int arr[16];
TestClass() {
for (int i = 0; i < 16; ++i) {
arr[i] = rand() % 100;
}
}
};
// sort by which fields
class Indicate {
public:
int ind[16];
};
struct SortA : public triple_function < TestClass, TestClass, const Indicate, bool >
{
bool operator () (const TestClass& a, const TestClass& b,
const Indicate& indicate) const
{
for (int i = 0; i < 16; ++i) {
int pos = indicate.ind[i];
if (a.arr[pos] == b.arr[pos]) {
continue ;
}
return a.arr[pos] < b.arr[pos];
}
return false;
}
};
int main() {
TestClass a[10];
Indicate ind;
for(int i = 0; i < 16; ++i) {
ind.ind[i] = i;
}
sort(a, a+10, bind3rd(SortA(), ind));
// bind3rd(SortA, ind);
}
when using g++ to compile, I got these compile error:
What's wrong with my code?
In file included from test.cpp:19:
triple_function.h:32: error: expected template-name before '<' token
triple_function.h:32: error: expected `{' before '<' token
triple_function.h:32: error: expected unqualified-id before '<' token
test.cpp: In function `int main()':
test.cpp:62: error: invalid use of undefined type `class binder3rd<SortA>'
triple_function.h:32: error: declaration of `class binder3rd<SortA>'
triple_function.h: In function `binder3rd<Operation> bind3rd(const Operation&, const Arg&) [with Operation = SortA, Arg = Indicate]':
test.cpp:62: instantiated from here
triple_function.h:52: error: return type `class binder3rd<SortA>' is incomplete
triple_function.h:53: error: invalid use of undefined type `class binder3rd<SortA>'
triple_function.h:32: error: declaration of `class binder3rd<SortA>'

The compiler is tripping over your binary_function base class. If you mean std::binary_function, then #include <functional> and the std:: prefix. Of course, since you're not actually defining a binary function, I'm not sure the base class is actually appropriate...
As others have said, std::bind is a better solution to this problem if you can use C++11.

Using std::bind instead, you could do e.g. like this:
#include <functional>
...
bool my_compare(const TestClass& a, const TestClass& b,
const Indicate& indicate)
{
...
}
int main()
{
...
using namespace std::placeholders;
std::sort(a, a+10, std::bind(my_compare, _1, _2, ind));
}

Related

Use a function pointer as template function type parameter?

#include <iostream>
#include <unordered_map>
#include <utility>
#include <typeinfo>
using namespace std;
class Handle{
public:
int val;
bool getAskPrice(int& tmp) const
{
tmp = val;
return true;
}
bool setAskPrice(int& tmp)
{
val = tmp;
return true;
}
};
template<class RT, class ARG>
struct convertToAFL{
static RT to_afl(ARG);
};
template<class RT, class ARG>
struct convertFromAFL{
static RT from_afl(ARG);
};
template<>
struct convertToAFL<float, int>
{
static float to_afl(int& value)
{
return static_cast<float>(value);
}
};
template<>
struct convertFromAFL<int, float>
{
static int from_afl(float& val)
{
return static_cast<int>(val);
}
};
struct Getter{
template<typename TICK_D, bool (Handle::*Getter)(TICK_D&) const, typename AFL_D>
static AFL_D getter(const Handle& handle)
{
TICK_D temp;
bool exists;
exists = (handle.*Getter)(temp);
AFL_D x = convertToAFL<AFL_D, TICK_D>::to_afl(temp);
return exists ? x : -1;
}
};
struct Setter{
template<typename TICK_D, bool (Handle::*Setter)(TICK_D&), typename AFL_D>
static void setter(Handle& handle, AFL_D& val)
{
TICK_D x;
x = convertFromAFL<TICK_D, AFL_D>::from_afl(val);
(handle.*Setter)(x);
}
};
int main()
{
Handle h;
float val = 20.0;
Setter::setter<int, &Handle::setAskPrice, float>(h, val);
std::cout<<Getter::getter<int, &Handle::getAskPrice, float>(h);
//std::pair<, &Setter::setter<int, &Handle::setAskPrice, float>> x;
return 0;
}
The above code works as expected, however, in the main() instead of calling the functions, how can I store the pointer to the templatized Setter:setter() and Getter::getter() ?
I m trying something like
std::pair<&Setter::setter<int, &Handle::setAskPrice, float>, &Getter::getter<int, &Handle::getAskPrice, float>(h)> func_pair;
And be able to call the functions later.
But i get an error saying
main.cpp: In function ‘int main()’:
main.cpp:85:118: error: type/value mismatch at argument 1 in template parameter list for ‘template struct std::pair’
std::pair<&Setter::setter<int, &Handle::setAskPrice, float>, &Getter::getter<int, &Handle::getAskPrice, float>(h)> func_pair;
^
main.cpp:85:118: note: expected a type, got ‘& setter’
main.cpp:85:118: error: template argument 2 is invalid
Static member functions are just a normal functions. You can store these pointers like this:
std::pair<void (*)(Handle& handle, float& val), float (*)(const Handle& handle)>
func_pair(&Setter::setter<int, &Handle::setAskPrice, float>, &Getter::getter<int, &Handle::getAskPrice, float>);
Your problem is that template parameter is a type, but you are passing a value (pointer) as an argument. Instead, you could use auto like this:
auto func_pair = std::make_pair(&Setter::setter<int, &Handle::setAskPrice, float>, &Getter::getter<int, &Handle::getAskPrice, float>);
Edit: if you are using C++03, std::make_pair() is still available, but not auto. You will need to describe the type manually with a series of typedefs.
You can use decltype to get the pointer type.
Example:
std::pair<int, decltype(&Setter::setter<int, &Handle::setAskPrice, float>)> x = {
1, &Setter::setter<int, &Handle::setAskPrice, float>
};
Prior to C++11:
std::pair<int, void(*)(Handle&, float&)> x(
1, &Setter::setter<int, &Handle::setAskPrice, float>
);

operator== does not compile if I include <iostream>

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).

A piece of code cannot be compiled by intel compiler but clang will compile it

The following code is a minimum working (or perhaps non-working) example.
What it does is basically encapsulates a bunch of std::map structures as private members in a base class. To avoid writing a lot of setters and getters, they are implemented as template functions.
// test.cpp
#include <map>
#include <iostream>
enum class E0
{
F0, F1, F2,
};
The declaration of the base class.
using std::map;
class P_base
{
private:
map<E0, int> m_imap;
// ...
// ... Other std::map members with different key types and value types.
public:
map<E0, int> & imap;
// ...
// ... Other std::map references.
P_base() : imap(m_imap) {}
template<typename map_type, typename key_type, typename val_type>
void set(map_type & m, const key_type & k, const val_type & v)
{
m[k] = v;
}
template<typename map_type, typename key_type>
auto access_to_map(const map_type & m, const key_type & k) -> decltype(m.at(k))
{
return m.at(k);
}
};
class P : private P_base
{
public:
decltype(P_base::imap) & imap;
P() : P_base(), imap(P_base::imap) {}
template<typename map_type, typename key_type, typename val_type>
void set(map_type & m, const key_type & k, const val_type & v)
{
P_base::set(m, k, v);
}
template<typename map_type, typename key_type>
auto access_to_map(const map_type & m, const key_type & k) -> decltype(P_base::access_to_map(m, k))
{
return P_base::access_to_map(m, k);
}
};
main
int main(int argc, const char * argv[])
{
using std::cout;
using std::endl;
P op;
op.set(op.imap, E0::F0, 100);
op.set(op.imap, E0::F1, 101);
op.set(op.imap, E0::F2, 102);
cout << op.access_to_map(op.imap, E0::F1) << endl;
}
$ clang++ -std=c++11 test.cpp && ./a.out
101
But if I compile it with intel compiler (icpc version 15.0.3 (gcc version 5.1.0 compatibility)), the compiler gives me this error message (which I don't undertand at all, especially when clang will compile the code):
$ icpc -std=c++ test.cpp && ./a.out
test.cpp(67): error: no instance of function template "P::access_to_map" matches the argument list
argument types are: (std::__1::map<E0, int, std::__1::less<E0>, std::__1::allocator<std::__1::pair<const E0, int>>>, E0)
object type is: P
cout << op.access_to_map(op.imap, E0::F1) << endl;
And it also confuses me by not complaining about the set function.
Does anyone have any idea what is going on here?
Note: My answer applies to g++ - hopefully it's the same as icc.
Here is a smaller test case:
struct Base
{
int func(int t) { return t; }
};
struct Der : Base
{
template<typename T>
auto f(T t) -> decltype(Base::func(t))
{
return t;
}
};
int main(){ Der d; d.f(5); }
The error is:
mcv.cc: In function 'int main()':
mcv.cc:16:25: error: no matching function for call to 'Der::f(int)'
int main(){ Der d; d.f(5); }
^
mcv.cc:16:25: note: candidate is:
mcv.cc:9:7: note: template<class T> decltype (t->Base::func()) Der::f(T)
auto f(T t) -> decltype(Base::func(t))
^
mcv.cc:9:7: note: template argument deduction/substitution failed:
mcv.cc: In substitution of 'template<class T> decltype (t->Base::func()) Der::f(T) [with T = int]':
mcv.cc:16:25: required from here
mcv.cc:9:38: error: cannot call member function 'int Base::func(int)' without object
auto f(T t) -> decltype(Base::func(t))
This can be fixed by changing decltype(Base::func(t)) to decltype(this->Base::func(t)). A corresponding fix fixes your code sample, for me.
Apparently, the compiler doesn't consider that Base::func(t) should be called with *this as hidden argument. I don't know if this is a g++ bug, or if clang is going beyond the call of duty.
Note that in C++14, since the function has a single return statement, the trailing return type can be omitted entirely:
template<typename T>
auto f(T t)
{
return t;
}

"Not declared in this scope" error resolving name of function template in a publicly derived base class template

Consider (link):
#include <cstdlib>
#include <cassert>
#pragma pack (1)
template <size_t Width>
class Base
{
public:
char mData [Width];
template <typename Field> Field ExtractAs () const
{
return *reinterpret_cast <Field> (mData);
}
};
template <typename FieldVal>
class IntegralField
:
public Base <sizeof (FieldVal)>
{
public:
FieldVal GetVal () const
{
return ExtractAs <FieldVal> ();
}
};
int main()
{
char raw[4] = {0x11, 0x22, 0x33, 0x44};
typedef IntegralField <uint32_t> UInt32Field;
const UInt32Field& field =
*reinterpret_cast <const UInt32Field*> (raw);
const uint32_t extracted = field.GetVal();
assert (extracted == 0x44332211);
}
The call:
return ExtractAs <FieldVal> ();
Fails to compile under g++ 4.7.2 with:
main.cpp: In member function ‘FieldVal IntegralField<FieldVal>::GetVal() const’:
main.cpp:25:16: error: ‘ExtractAs’ was not declared in this scope
main.cpp:25:35: error: expected primary-expression before ‘>’ token
main.cpp:25:38: error: expected primary-expression before ‘)’ token
main.cpp: In function ‘int main()’:
main.cpp:32:28: error: ‘uint32_t’ was not declared in this scope
main.cpp:32:36: error: template argument 1 is invalid
main.cpp:32:49: error: invalid type in declaration before ‘;’ token
main.cpp:35:11: error: ‘uint32_t’ does not name a type
main.cpp:36:5: error: ‘extracted’ was not declared in this scope
ninja: build stopped: subcommand failed.
I have tried a number of tricks including using Base::ExtractAs, typedefs, etc, to no avail.
Is what I'm trying to do possible in C++03? How can I call a function template in a base class template from a derived class template member function? Note that I cannot use C++11.
Edit: When I redefine GetVal to be more explicit about types:
FieldVal GetVal () const
{
static const size_t fieldSize = sizeof (FieldVal);
typedef Base <fieldSize> MyBase;
typedef FieldVal MyField;
return MyBase::ExtractAs <MyField> ();
}
I still get:
error: expected primary-expression before ‘>’ token
On: return MyBase::ExtractAs <MyField> ();
Edit: Here is the final, working code:
#include <cstdlib>
#include <cassert>
#include <stdint.h>
#pragma pack (1)
template <size_t Width>
class Base
{
public:
char mData [Width];
template <typename Field> Field ExtractAs () const
{
return *reinterpret_cast <const Field*> (mData);
}
};
template <typename FieldVal>
class IntegralField
:
public Base <sizeof (FieldVal)>
{
public:
FieldVal GetVal () const
{
return this->template ExtractAs<FieldVal>();
}
};
int main()
{
char raw[4] = {0x11, 0x22, 0x33, 0x44};
typedef IntegralField <uint32_t> UInt32Field;
const UInt32Field& field =
*reinterpret_cast <const UInt32Field*> (raw);
const uint32_t extracted = field.GetVal();
assert (extracted == 0x44332211);
}
You can either say:
return this->template ExtractAs<FieldVal>();
Or
return Base<sizeof(FieldVal)>::template ExtractAs<FieldVal>();
Since you are in a class template and the base is a template specialization, too, the names of base members are not automatically injected into the derived template. (Consider what happens if you specialize Base!)
By qualifying the name or using this->, you make the entire name dependent, and so it doesn't cause in error in the first phase. Also, since the name ExtractAs is dependent (being the nested name of a template), you have to disambiguate it as template.

Using a templated parameter's value_type

How is one supposed to use a std container's value_type?
I tried to use it like so:
#include <vector>
using namespace std;
template <typename T>
class TSContainer {
private:
T container;
public:
void push(T::value_type& item)
{
container.push_back(item);
}
T::value_type pop()
{
T::value_type item = container.pop_front();
return item;
}
};
int main()
{
int i = 1;
TSContainer<vector<int> > tsc;
tsc.push(i);
int v = tsc.pop();
}
But this results in:
prog.cpp:10: error: ‘T::value_type’ is not a type
prog.cpp:14: error: type ‘T’ is not derived from type ‘TSContainer<T>’
prog.cpp:14: error: expected ‘;’ before ‘pop’
prog.cpp:19: error: expected `;' before ‘}’ token
prog.cpp: In function ‘int main()’:
prog.cpp:25: error: ‘class TSContainer<std::vector<int, std::allocator<int> > >’ has no member named ‘pop’
prog.cpp:25: warning: unused variable ‘v’
I thought this was what ::value_type was for?
You have to use typename:
typename T::value_type pop()
and so on.
The reason is that the compiler cannot know whether T::value_type is a type of a member variable (nobody hinders you from defining a type struct X { int value_type; }; and pass that to the template). However without that function, the code could not be parsed (because the meaning of constructs changes depending on whether some identifier designates a type or a variable, e.g.T * p may be a multiplication or a pointer declaration). Therefore the rule is that everything which might be either type or variable and is not explicitly marked as type by prefixing it with typename is considered a variable.
Use the typename keyword to indicate that it's really a type.
void push(typename T::value_type& item)
typename T::value_type pop()
Here is a full implementation of the accepted answers above, in case it helps anyone.
#include <iostream>
#include <list>
template <typename T>
class C1 {
private:
T container;
typedef typename T::value_type CT;
public:
void push(CT& item) {
container.push_back(item);
}
CT pop (void) {
CT item = container.front();
container.pop_front();
return item;
}
};
int main() {
int i = 1;
C1<std::list<int> > c;
c.push(i);
std::cout << c.pop() << std::endl;
}
A fairly common practice is to provide an alias representing the underlying value type for convenience.
template <typename T>
class TSContainer {
private:
T container;
public:
using value_type = typename T::value_type;
void push(value_type& item)
{
container.push_back(item);
}
value_type pop()
{
value_type item = container.pop_front();
return item;
}
};