What is causing this template-related compile error? - c++

When I try to compile this:
#include <map>
#include <string>
template <class T>
class ZUniquePool
{
typedef std::map< int, T* > ZObjectMap;
ZObjectMap m_objects;
public:
T * Get( int id )
{
ZObjectMap::const_iterator it = m_objects.find( id );
if( it == m_objects.end() )
{
T * p = new T;
m_objects[ id ] = p;
return p;
}
return m_objects[ id ];
}
};
int main( int argc, char * args )
{
ZUniquePool< std::string > pool;
return 0;
}
I get this:
main.cpp: In member function ‘T* ZUniquePool<T>::Get(int)’:
main.cpp:12: error: expected `;' before ‘it’
main.cpp:13: error: ‘it’ was not declared in this scope
I'm using GCC 4.2.1 on Mac OS X.
It works in VS2008.
I'm wondering whether it might be a variation of this problem:
Why doesn't this C++ template code compile?
But as my error output is only partially similar, and my code works in VS2008, I am not sure.
Can anyone shed some light on what I am doing wrong?

You need typename:
typename ZObjectMap::const_iterator it = m_objects.find( id )
Since the type of ZObjectMap is dependent on the template parameter, the compiler has no clue what ZObjectMap::const_iterator is (it could be a member variable). You need to use typename to inform the compiler to assume it will be some sort of type.

Also to mention, GCC 4.5.0 gives the following output which would help you to solve the problem:
main.cpp: In member function 'T* ZUniquePool<T>::Get(int)':
main.cpp:12:7: error: need 'typename' before 'ZUniquePool<T>::ZObjectMap:: const_iterator' because 'ZUniquePool<T>::ZObjectMap' is a dependent scope
main.cpp:12:34: error: expected ';' before 'it'
main.cpp:13:11: error: 'it' was not declared in this scope
main.cpp: At global scope:
main.cpp:23:5: warning: second argument of 'int main(int, char*)' should be 'char **'

Related

g++ expects an unqualified-id, but what is it expecting?

I'm following a lesson on type aliases in a c++ book, and tried compiling the code below:
#include <cstdio>
#include <stdexcept>
template <typename To, typename From>
struct NarrowCaster const { //first error points here
To cast(From value) {
const auto converted = static_cast<To>(value);
const auto backwards = static_cast<From>(converted);
if(value != backwards) throw std::runtime_error{ "Narrowed!" };
return converted;
}
};
template <typename From>
using short_caster = NarrowCaster<short, From>; //second error
int main(){
try {
const short_caster<int> caster;
const auto cyclic_short = caster.cast(142857); //third error
printf("cyclic_short: %d\n", cyclic_short);
}catch(const std::runtime_error& e) {
printf("Exception: %s\n", e.what());
}
}
unfortunately, g++ (or clang++, because I'm using OS X) says this:
typealias.cpp|5 col 27 error| expected unqualified-id
which seems to also cause 2 more errors:
typealias.cpp|15 col 34 error| expected ';' after alias declaration
typealias.cpp|19 col 27 error| variable has incomplete type 'const short_caster<int>' (aka 'const NarrowCaster')
typealias.cpp|5 col 8 error| note: forward declaration of 'NarrowCaster'
I've tried fixing this issue, I'm already using std=c++17, and checked for non-ascii characters and made sure there aren't any differences from the code in the book. What am I doing wrong?
compiler command, if it helps:
g++ typealias.cpp -o typealias -std=c++17
struct NarrowCaster const {...
The const goes after a member function which means the function will not modify any data members:
To cast(From value) const {...}

class template fails to compile when named lambda is used as template class argument or constructor argument

I'm currently experimenting with class template programming and I came across this weird behavior that I cant understand when passing a named lambda as its argument. Could somebody explain why (1) & (2) below does not work?
template<typename Predicate>
class Test{
public:
Test(Predicate p) : _pred(p) {}
private:
Predicate _pred;
};
int main(){
auto isEven = [](const auto& x){ return x%2 == 0; };
// Working cases
Test([](const auto& x){ return x%2 == 0; });
Test{isEven};
auto testObject = Test(isEven);
// Compilation Error cases
Test(isEven); // (1) Why??? Most vexing parse? not assigned to a variable? I cant understand why this fails to compile.
Test<decltype(isEven)>(isEven); // (2) Basically same as (1) but with a workaround. I'm using c++17 features, so I expect automatic class parameter type deduction via its arguments
return 0;
};
Compiler Error message: Same for (1) & (2)
cpp/test_zone/main.cpp: In function ‘int main()’:
cpp/test_zone/main.cpp:672:16: error: class template argument deduction failed:
Test(isEven);
^
cpp/test_zone/main.cpp:672:16: error: no matching function for call to ‘Test()’
cpp/test_zone/main.cpp:623:5: note: candidate: template<class Predicate> Test(Predicate)-> Test<Predicate>
Test(Predicate p): _p(p){
^~~~
cpp/test_zone/main.cpp:623:5: note: template argument deduction/substitution failed:
cpp/test_zone/main.cpp:672:16: note: candidate expects 1 argument, 0 provided
Test(isEven);
^
Please forgive my formatting, and compile error message snippet as it does not match exact lines. I'm using g++ 7.4.0, and compiling with c++17 features.
In C++, you can declare a variable as
int(i);
which is the same as
int i;
In your case, the lines
Test(isEven);
Test<decltype(isEven)>(isEven);
are compiled as though you are declaring the variable isEven. I am surprised that the error message from your compiler is so different than what I hoped to see.
You can reproduce the problem with a simple class too.
class Test{
public:
Test(int i) : _i(i) {}
private:
int _i;
};
int main(){
int i = 10;
Test(i);
return 0;
};
Error from my compiler, g++ 7.4.0:
$ g++ -std=c++17 -Wall socc.cc -o socc
socc.cc: In function ‘int main()’:
socc.cc:15:11: error: conflicting declaration ‘Test i’
Test(i);
^
socc.cc:10:9: note: previous declaration as ‘int i’
int i = 10;
As you said, this is a most vexing parse issue; Test(isEven); is trying to redefine a variable with name isEven, and same for Test<decltype(isEven)>(isEven);.
As you showed, you can use {} instead of (), this is the best solution since C++11; or you can add additional parentheses (to make it a function-style cast).
(Test(isEven));
(Test<decltype(isEven)>(isEven));
LIVE

Nested Templates: "expected primary-expression before ')'"

i'm writing a Point class in c++ and use templates for this. But i have a compile error that i don't understand. I wrote a minimal example of the problem:
#include <array>
#include <vector>
#include <iostream>
template <typename T, int DIM>
class Point
{
private:
std::array<T, DIM> values;
public:
template <int ROW>
T get()
{
return values.at(ROW);
};
};
template <typename T>
class Field
{
public:
T print(std::vector<Point<T, 3> >& vec)
{
for (auto it : vec)
{
T bla = it.get<1>(); // the error line 27
}
};
};
int main(int argc,
char* argv[])
{
Point<double, 3> p;
double val = p.get<1>();
std::cout << val << std::endl;
Field<int> f;
std::vector<Point<int, 3> > vec;
f.print(vec);
return 0;
}
I compile with
g++ main2.cpp -std=c++11
and the output is
main2.cpp: In member function ‘T Field<T>::print(std::vector<Point<T, 3> >&)’:
main2.cpp:27:33: error: expected primary-expression before ‘)’ token
T bla = it.get< 1 >();
^
main2.cpp: In instantiation of ‘T Field<T>::print(std::vector<Point<T, 3> >&) [with T = int]’:
main2.cpp:41:16: required from here
main2.cpp:27:27: error: invalid operands of types ‘<unresolved overloaded function type>’ and ‘int’ to binary ‘operator<’
T bla = it.get< 1 >();
Does someone know why the error occurs and how to solve it?
Thank you.
Since it.get<1>() is dependent on a template parameter, you need to tell the compiler that get is a template so that it can be parsed correctly:
T bla = it.template get<1>();
Additionally, you don't return anything from that print function, even though the declaration says it should return a T.
See this question for more detail about the template keyword in this context.
Change the line
T bla = it.get<1>(); // the error line 27
to:
T bla = it.template get<1>(); // the error line 27
You need the template keyword to access template member functions if the class they're in is itself a template class.

C++ template argument with expression

I am having trouble with C++. I want to be able to put an expression inside a template as an argument. Here is my code:
#include <vector>
using namespace std;
vector< ((1>0) ? float : int) > abc() {
}
int main(void){
return 0;
}
This gives me the error:
main.cpp:11:14: error: template argument 1 is invalid
main.cpp:11:14: error: template argument 2 is invalid
main.cpp:11:15: error: expected unqualified-id before ‘{’ token
In the end I want to be able to replace 1 and 0 for whatever and also float and int for typename T and U. Why does it think there are two arguments? And how do I solve this?
(Sorry if this is a duplicate I did have a good look for solutions)
Use std::conditional:
#include <type_traits>
std::vector<std::conditional<(1 > 0), float, int>::type> abc() {}

Passing template typedef as argument to a function template

I am trying to pass a template typedef as argument to a function template. However I get following errors:
TestTemplates.cpp:11: error: expected unqualified-id before ‘&’ token
TestTemplates.cpp:11: error: expected unqualified-id before ‘&’ token
TestTemplates.cpp:11: error: expected initializer before ‘&’ token
TestTemplates.cpp:25: error: ‘func’ was not declared in this scope
#include <iostream>
#include <vector>
template<class T>
struct MyVector
{
typedef std::vector<T> Type;
};
template<class T>
void func( const MyVector<T>::Type& myVec )
{
for( MyVector<T>::Type::const_iterator p = myVec.begin(); p != myVec.end(); p++)
{
std::cout<<*p<<"\t";
}
}
int main()
{
MyVector<int>::Type myVec;
myVec.push_back( 10 );
myVec.push_back( 20 );
func( myVec );
}
Can anyone point out how to fix this error. I have looked at some posts, but cannot find the solution. Thanks
You need to tell the compiler that it's a typename
void func( const typename MyVector<T>::Type& myVec )
Then you need to explicitly help the compiler deduce the type for the function:
func<int>( myVec );
BTW, the issue is called "two stage lookup"