Access to private tuple element through a template member function [duplicate] - c++

This question already has answers here:
Where and why do I have to put the "template" and "typename" keywords?
(8 answers)
Closed 6 years ago.
The class foo contains a private tuple member. I want to get reference to an element of this tuple using a getElement<I>(). I came to this solution but it doesn't work when the object is passed to the constructor of another class bar:
#include <tuple>
template<class... Args>
class foo {
std::tuple<Args...> tup_;
public:
foo(Args... args) : tup_ {args...} {};
template<size_t I>
const typename std::tuple_element<I, std::tuple<Args...>>::type &
getElement() const {return std::get<I>(tup_);}
};
template<class T>
class bar;
template<class T, class U>
class bar<foo<T,U>> {
public:
bar(foo<T,U> f) {
auto j = f.getElement<0>(); // this is an ERROR!!! Line 22
}
};
int main()
{
foo<int, char> f(12,'c');
auto j = f.getElement<0>(); // but this is OK!
bar<decltype(f)> b(f);
return 0;
}
compiler output:
main.cpp: In constructor 'bar<foo<T, U> >::bar(foo<T, U>)':
main.cpp:22:33: error: expected primary-expression before ')' token
auto j = f.getElement<0>(); // this is an ERROR!!!
^
main.cpp: In instantiation of 'bar<foo<T, U> >::bar(foo<T, U>) [with T = int; U = char]':
main.cpp:32:24: required from here
main.cpp:22:29: error: invalid operands of types '<unresolved overloaded function type>' and 'int' to binary 'operator<'
auto j = f.getElement<0>(); // this is an ERROR!!!

You must warn the compiler that getElement is a template method. And to do it you must specify the template keyword, eg:
f.template getElement<0>()
This because otherwise the compiler tries to parse the code as f.getElement < 0 so that it tries to call the binary operator< on f.getElement and 0 which is not what you want to do.

Related

C++: Why can't I invoke a template member function of a template parameter type? [duplicate]

This question already has answers here:
Where and why do I have to put the "template" and "typename" keywords?
(8 answers)
Closed 6 months ago.
I am writing a template function where one of the template parameters is a type with a member function that is itself a template function. When I invoke the template member function and explicitly specify the template parameters, it appears that the code does not compile. This is illustrated in the following minimal example:
This version will compile and run just fine:
#include <iostream>
struct ar_t
{
int data[2];
ar_t(void) {data[0] = 10; data[1] = 17;}
template <const std::size_t idx> int get(void) const {return data[idx];}
};
template <const std::size_t val> struct idx_t {};
template <const std::size_t val> int idx_ar1(const ar_t& ar, const idx_t<val>& idx)
{
return ar.get<val>();
}
int main(int argc, char** argv)
{
ar_t x;
const std::size_t index = 1;
idx_t<index> i;
idx_ar1(x,i);
return 0;
}
whereas this version will not:
#include <iostream>
struct ar_t
{
int data[2];
ar_t(void) {data[0] = 10; data[1] = 17;}
template <const std::size_t idx> int get(void) const {return data[idx];}
};
template <const std::size_t val> struct idx_t {};
template <typename arr_type, const std::size_t val> int idx_ar1(const arr_type& ar, const idx_t<val>& idx)
{
return ar.get<val>();
}
int main(int argc, char** argv)
{
ar_t x;
const std::size_t index = 1;
idx_t<index> i;
idx_ar1(x,i);
return 0;
}
Note the difference in the template parameters for idx_ar1. The error message I get with g++ 11.1 and -std=c++20 is:
main.cc: In function ‘int idx_ar1(const arr_type&, const idx_t<val>&)’:
main.cc:14:24: error: expected primary-expression before ‘)’ token
14 | return ar.get<val>();
| ^
main.cc: In instantiation of ‘int idx_ar1(const arr_type&, const idx_t<val>&) [with arr_type = ar_t; long unsigned int val = 1]’:
main.cc:22:12: required from here
main.cc:14:18: error: invalid operands of types ‘<unresolved overloaded function type>’ and ‘long unsigned int’ to binary ‘operator<’
14 | return ar.get<val>();
|
How can I get around this? I require preciesly the behaviour used in the second example. This appears to be a bug in parsing the syntax, or I don't quite have a detailed understanding of the way the member function is being declared.
Try compiling with Clang, too - sometimes it gives better errors than GCC (sometimes worse):
":14:15: error: missing 'template' keyword prior to dependent template name 'get'"

Why can I not pass a numeric template parameter to my templated function? [duplicate]

This question already has answers here:
Where and why do I have to put the "template" and "typename" keywords?
(8 answers)
Closed 11 months ago.
I have a custom class encapsulating a std::tuple ("MyTuple") and another class implementing a custom interface for a std::tuple ("MyInterface"). I need this separate interface in the code base, the code below is simplified.
Since elements of std::tuple need to be accessed with the key as template parameter, the interface's functions have a numeric template parameter size_t Key which is then given to std::get for the tuple for example.
This interface works fine, but not when calling it from another templated function which passes a numeric parameter as "key":
#include <iostream>
#include <functional>
#include <tuple>
#include <string>
template <typename... Types>
class MyInterface {
public:
MyInterface(const std::tuple<Types...>& tuple) : tuple(tuple) {}
template <size_t Key>
std::string getString() {
return std::to_string(std::get<Key>(tuple));
}
private:
const std::tuple<Types...>& tuple;
};
template <typename... Types>
class MyTuple {
public:
MyTuple(Types... values) : value(std::tuple<Types...>(values...)) {}
template <size_t Key>
std::string asString() {
MyInterface<Types...> interface(value);
return interface.getString<Key>(); // here I get the compiler error
}
private:
std::tuple<Types...> value;
};
int main() {
MyInterface<int, float, long> interface(std::tuple<int, float, long>(7, 3.3, 40));
std::cout << interface.getString<0>() << std::endl; // this works fine
MyTuple<int, float, long> tuple(7, 3.3, 40);
std::cout << tuple.asString<0>() << std::endl;
}
Complete output of g++:
templated_function_parameter_pack.cpp: In member function ‘std::__cxx11::string MyTuple<Types>::asString()’:
templated_function_parameter_pack.cpp:28:39: error: expected primary-expression before ‘)’ token
return interface.getString<Key>(); // here I get the compiler error
^
templated_function_parameter_pack.cpp: In instantiation of ‘std::__cxx11::string MyTuple<Types>::asString() [with long unsigned int Key = 0; Types = {int, float, long int}; std::__cxx11::string = std::__cxx11::basic_string<char>]’:
templated_function_parameter_pack.cpp:40:34: required from here
templated_function_parameter_pack.cpp:28:33: error: invalid operands of types ‘<unresolved overloaded function type>’ and ‘long unsigned int’ to binary ‘operator<’
return interface.getString<Key>(); // here I get the compiler error
Why is not valid syntax to call interface.getString<Key>() inside MyTuple::asString<size_t Key>?
When you want to call a template method of an instance, you need to write this:
return interface.template getString<Key>();
You'll find every details of why in this answer: Where and why do I have to put the "template" and "typename" keywords?

C++ parameter pack usage [duplicate]

This question already has answers here:
Where and why do I have to put the "template" and "typename" keywords?
(8 answers)
Closed 1 year ago.
I want to encapsulate a class which uses template parameter pack and function template into another similar class, like the following example:
#include <iostream>
template<typename ... Args>
struct O2 {
template<int T>
void f() {
}
};
template<typename ... Args>
struct O1 {
O2<Args...> i2;
template<int T>
void g() {
i2.f<T>();
}
};
int main()
{
O1<int> i1;
i1.g<1>();
return 0;
}
but the compliler it says I'm wrong:
main.cpp: In member function 'void O1<Args>::g()':
main.cpp:18:17: error: expected primary-expression before ')' token
18 | i2.f<T>();
| ^
main.cpp: In instantiation of 'void O1<Args>::g() [with int T = 1; Args = {int}]':
main.cpp:25:12: required from here
main.cpp:18:13: error: invalid operands of types '<unresolved overloaded function type>' and 'int' to binary 'operator<'
18 | i2.f<T>();
| ~~~~^~
I can't modify the inner class (O2), and I can't use inheritance. Any idea how to do it?
Thx
The correct syntax is:
i2.template f<T>();

Class vs. function template specialization [duplicate]

This question already has answers here:
C++ template specialization for pointer?
(3 answers)
Closed 2 years ago.
I only recently learned about partial template specialization in C++ from here, and it perfectly solved a problem where I needed a template class to behave differently for pointers and non-pointers. A simplified example is:
// main.cpp
template <typename T>
class C
{
public:
C( const T& t ) : t_( t ) {}
private:
T t_;
};
template <typename T>
class C<T*>
{
public:
C( const T& t ) : t_( new T(t) ) {}
~C() { delete t_; }
private:
T* t_;
};
int main( int argc, char* argv[] )
{
C<int> c1(4);
C<int*> c2(2);
return 0;
}
I wanted to try extend this idea to functions, but ran into compiler errors I didn't understand:
// main.cpp
#include <set>
template <typename T>
std::set<T> makeSet( size_t off )
{
std::set<T> s;
s.insert( T() + T(off) );
return s;
}
template <typename T>
std::set<T*> makeSet<T*>( size_t off )
{
std::set<T*> s;
T* t = new T( T() + T(off) );
s.insert( t );
return s;
}
int main( int argc, char* argv[] )
{
std::set<int> s1 = makeSet<int>(4);
std::set<int*> s2 = makeSet<int*>(2);
delete *(s2.begin());
return 0;
}
.
$ g++ --version && g++ -g ./main.cpp
g++ (GCC) 9.2.1 20190827 (Red Hat 9.2.1-1)
Copyright (C) 2019 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
./main.cpp:13:38: error: non-class, non-variable partial specialization ‘makeSet<T*>’ is not allowed
13 | std::set<T*> makeSet<T*>( size_t off )
| ^
./main.cpp: In function ‘int main(int, char**)’:
./main.cpp:23:37: error: call of overloaded ‘makeSet<int>(int)’ is ambiguous
23 | std::set<int> s1 = makeSet<int>(4);
| ^
./main.cpp:5:13: note: candidate: ‘std::set<T> makeSet(size_t) [with T = int; size_t = long unsigned int]’
5 | std::set<T> makeSet( size_t off )
| ^~~~~~~
./main.cpp:13:14: note: candidate: ‘std::set<T*> makeSet(size_t) [with T = int; size_t = long unsigned int]’
13 | std::set<T*> makeSet<T*>( size_t off )
| ^~~~~~~~~~~
./main.cpp:24:38: error: call of overloaded ‘makeSet<int*>(int)’ is ambiguous
24 | std::set<int*> s2 = makeSet<int*>(2);
| ^
./main.cpp:5:13: note: candidate: ‘std::set<T> makeSet(size_t) [with T = int*; size_t = long unsigned int]’
5 | std::set<T> makeSet( size_t off )
| ^~~~~~~
./main.cpp:13:14: note: candidate: ‘std::set<T*> makeSet(size_t) [with T = int*; size_t = long unsigned int]’
13 | std::set<T*> makeSet<T*>( size_t off )
| ^~~~~~~~~~~
I was a little skeptical about this because it looks like an attempt at overloading a function with a different return-type but with the same arguments - I know this is otherwise illegal, but I thought that because these were template functions, specifying the template type when invoking the functions (as in the above main()) would allow disambiguation.
But I'm not sure that's what the compiler is complaining about on line 13: what does the non-class, non-variable partial specialization ‘makeSet<T*>’ is not allowed error mean?
Is what I'm trying to do even possible in C++? I.e. can a template function be made so that it behaves differently for pointers and non-pointer template types and return a STL container of the specified type? (Would the answer be different between C++ 98, 03, 11, and 14?)
what does the non-class, non-variable partial specialization ‘makeSet<T*>’ is not allowed error mean?
Let's take a look at some documentation from cppreference.com regarding partial template specialization:
Allows customizing class [and variable (since C++14)] templates for a given category of template arguments.
Partial specializations are allowed for class and variable templates. The compiler has told you that your template is for neither a class for a variable. Therefore, partial specialization is not allowed.
A less confusing wording for the compiler's message would be: partial specialization of function templates is not allowed.
As for what can be done, it is possible to declare a class template with a suitable operator(). In some cases this is about as good as using a function template.
You can try something like this (C++17):
template <typename T>
std::set<T> makeSet( size_t off )
{
std::set<T> s;
if constexpr(std::is_pointer_v<T>)
{
using U = std::remove_reference_t<decltype(*std::declval<T>())>;
s.insert(new U( U() + U(off) ));
}
else
{
s.insert( T() + T(off) );
}
return s;
}

Address of templated member function [duplicate]

This question already has answers here:
Where and why do I have to put the "template" and "typename" keywords?
(8 answers)
Closed 9 years ago.
In the example below, how do I find the address of the member function f
template<typename HANDLER>
void serialize(HANDLER &h) {
// Compiler error (gcc 4.8.1)
// test.cxx: In function ‘void serialize(HANDLER&)’:
// test.cxx:9:26: error: expected primary-expression before ‘int’
// auto x = &HANDLER::f<int>;
// ^
// test.cxx:9:26: error: expected ‘,’ or ‘;’ before ‘int’
auto x = &HANDLER::f<int>;
}
struct HandlerA {
template<typename T> void f() { }
};
struct HandlerB {
template<typename T> void f() { }
};
struct HandlerC {
template<typename T> void f() { }
};
int main() {
HandlerA a;
HandlerB b;
HandlerC c;
a.f<int>();
b.f<int>();
c.f<int>();
serialize(a);
serialize(b);
serialize(c);
}
You need to tell the compiler that f is a template so that it can parse the function correctly:
auto x = &HANDLER::template f<int>;
Casey is correct.
A template, before instantiation has no address. as the template is used (instantiated) with specific parameters, a unique function in memory is created.
You can use/create a real function with any type: int, char, float, double, classXYZ... there's no limit to how many pointers to that function there could be.