Template and typename - c++

The following code is compiled with error msg:
#> g++ test.cpp
test.cpp: In member function 'void testit<E>::print()':
test.cpp:79: error: 'COL' is not a class or namespace
test.cpp:83: error: expected `;' before 'b2'
If I use COL::columns; to access static member, it wont compile successfully.
instead, access static member by SelectColumn::SELECT_COLS::columns; will be oK!
struct AllColumns
{
static const char columns[];
};
const char AllColumns::columns[] = "*";
struct MemoryColumns
{
static const char columns[];
};
const char MemoryColumns::columns[] = "data,data_expire_time";
template<typename E>
struct SelectColumn
{
public:
typedef unsigned BIGT;
typedef AllColumns SELECT_COLS;
};
template<>
struct SelectColumn<int>
{
public:
typedef int BIGT;
typedef MemoryColumns SELECT_COLS;
};
template<typename E>
class testit
{
public:
typename SelectColumn<E>::SELECT_COLS COL;
typename SelectColumn<E>::BIGT BIG;
void print()
{
string str_a = COL::columns; //compile error here!
string str_b = SelectColumn<E>::SELECT_COLS::columns; // OK
BIG b2 = 10; //compile error here!
typename SelectColumn<E>::BIGT b = 12; // OK
}
};
How to fix it if I want to use COL::columns ?
thanks!

typename SelectColumn<E>::SELECT_COLS COL;
is a variable declaration, not a type. (The name of the variable is COL, the type is typename SelectColumn<E>::SELECT_COLS)
Perhaps you meant to say
typedef typename SelectColumn<E>::SELECT_COLS COL;

typename SelectColumn<E>::SELECT_COLS COL;
typename used here is not a syntax to make COL an alias of SelectColumn<E>::SELECT_COLS, but to tell the parser that the identifier SELECT_COLS is a type and not a variable.
str_a = COL::columns;
The reason why you got an error at this line, is because you are trying to access a member data of theCOL object using wrong syntax.

COL is an object, not a type, as such you must say COL.columns to accees members of it.

Related

Is there a way to get pointer-to-member without mentioning the class name if it is used within the context of the class

The code below gives the following compilation error:
main.cpp:5:48: error: invalid use of non-static data member 'id'
static constexpr int Type::* mem_ptr_id = &id;
^~
main.cpp:5:34: error: default initialization of an object of const type 'int Type::*const'
static constexpr int Type::* mem_ptr_id = &id;
^
= nullptr
main.cpp:6:46: error: invalid use of non-static data member 'id'
static constexpr auto mem_ptr_id_auto = &id;
^~
main.cpp:6:27: error: declaration of variable 'mem_ptr_id_auto' with deduced type 'const auto' requires an initializer
static constexpr auto mem_ptr_id_auto = &id;
^
4 errors generated.
which is kind of expected.
#include <iostream>
struct Type {
int id;
static constexpr int Type::* mem_ptr_id = &id; // &Type::id required
static constexpr auto mem_ptr_id_auto = &id; // &Type::id required
};
int main() {
Type test;
test.*Type::mem_ptr_id = 5; // same as test.id = 5
test.*Type::mem_ptr_id_auto = 5; // same as test.id = 5
std::cout << test.id << std::endl; // expected: 5
return 0;
}
I need a way to have static pointer-to-member variable of my class/structure without explicitly naming the type (class/struct) name. Any suggestions?
Note:
In order to avoid auto to become int&, I did pointer-to-member wrapper:
template<typename T, class E>
struct Pointer2Member {
using var_t = T;
using entity_t = E;
using mem_ptr_t = T E::*;
T E::* data;
constexpr Pointer2Member() {}
constexpr Pointer2Member(T E::* val) : data(val) {}
constexpr operator T E::* () {
return data;
}
};
template<auto ptr>
struct Pointer2MemberOf;
template<typename T, class E, T E::* ptr>
struct Pointer2MemberOf<ptr> : Pointer2Member<T, E> {
constexpr Pointer2MemberOf() : Pointer2Member<T, E>(ptr) {}
constexpr operator Pointer2Member<T, E>() {
return *this;
}
};
struct Type {
int id;
static constexpr auto mem_ptr_id = Pointer2MemberOf<&id>(); // Pointer2MemberOf<&Type::id>() required
};
but it gives same error:
main.cpp:34:58: error: invalid use of non-static data member 'id'
static constexpr auto mem_ptr_id = Pointer2MemberOf<&id>();
^~
main.cpp:34:27: error: declaration of variable 'mem_ptr_id' with deduced type 'const auto' requires an initializer
static constexpr auto mem_ptr_id = Pointer2MemberOf<&id>();
^
main.cpp:40:17: error: no member named 'mem_ptr_id_auto' in 'Type'
test.*Type::mem_ptr_id_auto = 5; // same as test.id = 5
~~~~~~^
3 errors generated.
Note 2: Follow-up on the comment "What do you need this for":
Unfortunately, it is very complicated variadic template solution which I can't talk a lot about.
What I want to achieve is to create a template class Result<...> which can store custom member variables of different classes.
Result<User::id, User::username, Post::id> and Result<User, Post::id> should both be viable syntaxes and should have Result<User, Post::id>::get<PROPERTY> which should be able to have both Result<User, Post::id>::get<User> and Result<User, Post::id>::get<User::id> (yes, User, not Post).
Imagine Result<...> class in a library that will be used by beginner C++ programmers so I don't want to use the &User::id syntax as it might be too complicated to comprehend for them.
Also, the static member will be auto-generated via macros like
#define Member(TYPE, NAME) TYPE _##NAME; static constexpr auto NAME = Pointer2Member(&_##NAME)
struct User {
Member(int, id);
Member(std::string, username);
};
Result<User::id> result1;
result1.get<User::id>() = 5;
Result<User> result2;
result2.get<User::id>() = 6;
result2.get<User::username>() = "John";

Map enum value to template argument in C++

I have an enum class with several members. The goal of the enum is to encode primitive types (e.g. int, long, float, ...) at runtime, so that it's possible to store this information in a database for example. At the same time a lot of classes templated to work on primitive types exist as well.
The problem: I want to create an object from such a templated class, given an enum value that is not a constant. Would this be possible in any way that is cleaner and more scalable than creating a long switch on the enum values (or doing essentially the same with a map as proposed in the answer of Dynamic mapping of enum value (int) to type)?
Here's something I've been trying hoping that template type inference could work, but it fails to compile (can be checked here for example: http://rextester.com/VSXR46052):
#include <iostream>
enum class Enum {
Int,
Long
};
template<Enum T>
struct EnumToPrimitiveType;
template<>
struct EnumToPrimitiveType<Enum::Int> {
using type = int;
};
template<>
struct EnumToPrimitiveType<Enum::Long> {
using type = long;
};
template<typename T>
class TemplatedClass
{
public:
TemplatedClass(T init): init{init} {}
void printSize() { std::cout << sizeof(init) << std::endl; }
private:
T init;
};
template<Enum T>
auto makeTemplatedClass(T enumValue) -> TemplatedClass<EnumToPrimitiveType<T>::type>
{
TemplatedClass<EnumToPrimitiveType<T>::type> ret(5);
return ret;
}
int main()
{
Enum value{Enum::Int};
auto tmp = makeTemplatedClass(value);
tmp.printSize();
}
Compile error:
source_file.cpp:36:27: error: expected ‘)’ before ‘enumValue’
auto makeTemplatedClass(T enumValue) -> TemplatedClass<EnumToPrimitiveType<T>::type>
^
source_file.cpp:36:6: warning: variable templates only available with -std=c++14 or -std=gnu++14
auto makeTemplatedClass(T enumValue) -> TemplatedClass<EnumToPrimitiveType<T>::type>
^
source_file.cpp:36:38: error: expected ‘;’ before ‘->’ token
auto makeTemplatedClass(T enumValue) -> TemplatedClass<EnumToPrimitiveType<T>::type>
^
source_file.cpp: In function ‘int main()’:
source_file.cpp:44:16: error: ‘A’ is not a member of ‘Enum’
Enum value{Enum::A};
^
source_file.cpp:45:34: error: missing template arguments before ‘(’ token
auto tmp = makeTemplatedClass(value);
^
Problems I see:
You cannot use template<Enum T> auto makeTemplatedClass(T enumValue) since T is not a type. You need to use just template<Enum T> auto makeTemplatedClass() and invoke the function differently.
You need to use TemplatedClass<typename EnumToPrimitiveType<T>::type> instead of just TemplatedClass<EnumToPrimitiveType<T>::type>. That is necessary since type is a dependent type.
You cannot use value as a template parameter unless it is a const or constexpr.
The following program compiles and builds on my desktop.
#include <iostream>
enum class Enum {
Int,
Long
};
template<Enum T>
struct EnumToPrimitiveType;
template<>
struct EnumToPrimitiveType<Enum::Int> {
using type = int;
};
template<>
struct EnumToPrimitiveType<Enum::Long> {
using type = long;
};
template<typename T>
class TemplatedClass
{
public:
TemplatedClass(T init): init{init} {}
void printSize() { std::cout << sizeof(init) << std::endl; }
private:
T init;
};
template<Enum T>
auto makeTemplatedClass() -> TemplatedClass<typename EnumToPrimitiveType<T>::type>
{
TemplatedClass<typename EnumToPrimitiveType<T>::type> ret(5);
return ret;
}
int main()
{
Enum const value{Enum::Int};
auto tmp = makeTemplatedClass<value>();
tmp.printSize();
}

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

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));
}

Compilation error with Type Traits in boost::type_traits::conditional

I am having a problem in some code using type_traits from boost.
It is quite a complex part of the code, but I could isolate the part that gives the compilation error:
template<const size_t maxLen>
class MyString {
public:
typedef boost::conditional<(maxLen > 0), char[maxLen+1], std::string> ObjExternal;
};
template <class T>
class APIBase {
public:
typedef T obj_type;
typedef typename T::ObjExternal return_type;
};
template <class T>
int edit(const T& field, const typename T::return_type& value)
{
return 0;
}
int myFunction()
{
APIBase<MyString<10> > b;
char c[11];
return edit(b, c);
}
This gives the following error:
test.cpp: In function ‘int myFunction()’:
tes.cpp:109: error: no matching function for call to ‘edit(APIBase >&, char [11])’
tes.cpp:100: note: candidates are: int edit(const T&, const typename T::return_type&) [with T = APIBase >]
However, if I change the line with the code
char c[11];
by
MyString<10>::ObjExternal c;
it works. Similarly, if instead I change the line
typedef boost::conditional<(maxLen > 0), char[maxLen+1], std::string> ObjExternal;
by
typedef char ObjExternal[maxLen+1];
it also works. I am thinking that it is a problem with boost::conditional, as it seems it is not being evaluated right. Is there a problem in my code, or there is an alternative that can be used instead of boost::conditional to have this functionality?
I am thinking about using the 2nd option, but then I could not use maxLen as 0.
You need to use the member typedef type provided by conditional and not the conditional type itself.
Change:
typedef boost::conditional<(maxLen > 0),
char[maxLen+1],
std::string> ObjExternal;
to:
typedef typename boost::conditional<(maxLen > 0),
char[maxLen+1],
std::string>::type ObjExternal;

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;
}
};