clang error while compiling template [duplicate] - c++

This question already has answers here:
Where and why do I have to put the "template" and "typename" keywords?
(8 answers)
Closed 5 years ago.
I am trying to touch C++17 features and I have selected clang.
Here is simplified example of my code that could not be compiled via clang:
#include <iostream>
#include <limits>
template<
typename T,
template<typename T_> typename Final>
class Base
{
public:
decltype(auto) Foo() const noexcept
{
using TFinal = Final<T>;
auto& _this = static_cast<const TFinal&>(*this);
return _this.Bar<true>();
}
};
template<typename T>
class Derived :
public Base<T, ::Derived>
{
public:
template<bool min>
T Bar() const noexcept
{
return min ?
std::numeric_limits<T>::lowest() :
std::numeric_limits<T>::max();
}
};
int main()
{
Derived<int> instance;
auto result = instance.Foo();
std::cout << result << std::endl;
return 0;
}
It fails here:
return _this.Bar<true>();
and error message is:
main.cpp:14:32: error: expected expression
return _this.Bar<true>();
^
main.cpp:35:10: error: variable has incomplete type 'void'
auto result = instance.Foo();
^
Here is how I am compiling it:
clang++-5.0 main.cpp -std=c++17
Some additional info. Visual Studio 17 with latest language version can eat this. When bar function is not template, everything is ok...
Any suggestions what is wrong here?

Should be
return _this.template Bar<true>();
In your case _this has dependent type. To refer to its member templates you have to use the keyword template explicitly.
Where and why do I have to put the "template" and "typename" keywords?

Related

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?

Access to private tuple element through a template 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 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.

GCC Templates: expected »(« before »>« token [duplicate]

This question already has answers here:
Where and why do I have to put the "template" and "typename" keywords?
(8 answers)
Closed 7 years ago.
I don't understand why the following code doesn't compile:
template< typename TypeArg >
class Data
{
public:
struct Selector1
{
};
template< typename Selector >
void foo()
{
}
};
template< typename TypeArg >
class Test
{
public:
void test();
};
template< typename TypeArg >
void Test< TypeArg >::test()
{
Data< TypeArg > data;
data.foo< typename Data< TypeArg >::Selector1 >();
}
I have tested it with GCC 4.6 and GCC 4.9. Both give me the same error:
test.cpp: In member function »void Test::test()«:
test.cpp:28:51: Error: expected »(« before »>« token
test.cpp:28:53: Error: expected primary-expression before »)« token
Can somebody tell me what needs to be done for the code to compile?
Since the type of data is dependent, the nature of data.foo is not known and needs to be disambiguated:
data.template foo<typename Data< TypeArg >::Selector1>();
// ^^^^^^^^

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.

Two templates in C++: "expected primary-expression before ‘>’ token" [duplicate]

This question already has answers here:
Where and why do I have to put the "template" and "typename" keywords?
(8 answers)
Closed 7 years ago.
Minmal working example:
#include <iostream>
struct Printer
{
template<class T>
static void print(T elem) {
std::cout << elem << std::endl;
}
};
template<class printer_t>
struct Main
{
template<class T>
void print(T elem) {
// In this case, the compiler could guess T from the context
// But in my case, assume that I need to specify T.
printer_t::print<T>(elem);
}
};
int main()
{
Main<Printer> m;
m.print(3);
m.print('x');
return 0;
}
My compiler (g++) gives me the error "expected primary-expression before ‘>’ token". What's wrong and how to fix it?
C++11 accepted.
clang gives a better error message in this case:
$ clang++ example.cpp -o example
example.cpp:18:20: error: use 'template' keyword to treat 'print' as a dependent template name
printer_t::print<T>(elem);
^
template
1 error generated.
Just add the template where it says to, and you're set.