This question already has answers here:
Trouble with dependent types in templates
(2 answers)
Closed 1 year ago.
I have the following code.
template<class key,class val>
bool has_key(key chkey,std::map<key,val> map){
for (std::map<key,val>::iterator it = map.begin(); #line 13 referenced by gcc
it!=map.end(); ++it){
if(chkey == it->first) return true;
}
return false;
}
GCC is giving me the following error.
objects.hpp: In function `bool has_key(key, std::map<key, val, std::less<_Key>,
std::allocator<std::pair<const _Key, _Tp> > >)':
objects.hpp:13: error: expected `;' before "it"
objects.hpp:14: error: `it' was not declared in this scope
Somehow "it" is not being initialized, what in Sam Hain is going on here?!
You need the typename keyword:
for (typename std::map<key,val>::iterator it = map.begin(); #line 13 referenced by gcc
it!=map.end(); ++it){
See also: Why do we need typename here?
This is because you are in a template definition and iterator is a dependent name. This has been asked before.
g++ "is not a type" error
C++ Template: 'is not derived from type'
Trouble with dependent types in templates
Related
I added the following function template to my project, and a user complained that it wouldn't compile on their system anymore:
template<typename T>
std::size_t removeDuplicates(std::vector<T>& vec)
{
std::unordered_set<T> seen;
auto newEnd = std::remove_if(
vec.begin(), vec.end(), [&seen](const T& value)
{
if (seen.find(value) != std::end(seen))
return true;
seen.insert(value);
return false;
}
);
vec.erase(newEnd, vec.end());
return vec.size();
}
The error message with g++ 9.4 was approximately
error: use of deleted function
'std::unordered_set<_Value, _Hash, _Pred, _Alloc>::unordered_set()
[with
_Value = std::filesystem::__cxx11::path;
_Hash = std::hash<std::filesystem::__cxx11::path>;
_Pred = std::equal_to<std::filesystem::__cxx11::path>;
_Alloc = std::allocator<std::filesystem::__cxx11::path>]'
12 | std::unordered_set<T> seen;
So the error arose when instantiating the above function template with T = std::filesystem::path.
I investigated a little and found that there was no issue when instantiating it with other types, e.g. fundamental types or std::string, but only with std::filesystem::path.
Using Compiler Explorer, I looked at how different compiler versions treat the code and found that only g++ v.12 can compile the instantiation with std::filesystem::path. Any g++ version below 12 fails with the above error. clang produces a similar error (call to implicitly deleted default constructor), even on the newest version (14). I didn't test other compilers.
The workaround I used was substituting std::unordered_set with std::set. Then it works on g++ v.8 and clang v.7 and above.
So I guess the error is a missing hashing function for std::filesystem::path? Or is it an error on my part?
The std::hash specialization for std::filesystem::path has only recently been added as resolution of LWG issue 3657 into the standard draft. It hasn't been there in the published C++17 and C++20 standards.
There has always been however a function std::filesystem::hash_value from which you can easily create a function object to pass as hash function to std::unordered_set:
struct PathHash {
auto operator()(const std::filesystem::path& p) const noexcept {
return std::filesystem::hash_value(p);
}
};
//...
std::unordered_set<std::filesystem::path, PathHash> seen;
If you are providing that template without any guarantees that it works on types other than those that have a std::hash specialization defined, then I think there is no problem on your part.
However, if you require the type to be hashable, it would be a good idea to let the user override the hash function used the same way std::unordered_set does. The same also applies to the equality functor used.
This question already has answers here:
Where and why do I have to put the "template" and "typename" keywords?
(8 answers)
Closed 2 years ago.
When I attempt to call the method target on a std::function object using a template parameter pack, the compiler throws an error, but it works fine if the template parameters are specified explicitly in a proxy variable.
Example, modified from cppreference.com:
#include <functional>
#include <iostream>
int f(int, int) { return 1; }
int g(int, int) { return 2; }
template <typename... Args>
void test(std::function<int(Args...)> const& arg)
{
auto && ptr = arg.target<int(*)(Args...)>(); // error: expected primary-expression before 'int'
if (ptr && *ptr == f)
std::cout << "it is the function f\n";
if (ptr && *ptr == g)
std::cout << "it is the function g\n";
}
int test()
{
test<int, int>(std::function<int(int, int)>(f));
test<int, int>(std::function<int(int, int)>(g));
}
I've tried various other ways to call target including the following:
int (*const* ptr)(Args...) = arg.target<int(*)(Args...)>(); // error: expected primary-expression before 'int'
int (*const* ptr)(int, int) = arg.target<int(*)(Args...)>(); // error: expected primary-expression before 'int'
int (*const* ptr)(int, int) = arg.target<int(*)(int, int)>(); // error: expected primary-expression before 'int'
const std::function<int(Args...)>& func = arg;
auto && ptr = arg.target<int(*)(Args...)>(); // error: expected primary-expression before 'int'
The compiler only appeared to be satisfied when using a proxy variable as seen here:
const std::function<int(int, int)>& func = arg;
auto && ptr = func.target<int(*)(Args...)>(); // OK, but requires specifying the template arguments for func
As can be seen, this workaround deviates from the previous non-working example only by explicitly specifying the function parameters instead of relying on the parameter pack. (I could bypass the proxy variable with a static_cast e.g. static_cast<std::function<int(int,int)>&>(arg).target<int(*)(Args...)>(), but this also requires knowing the parameters for the cast.) If I already knew what parameters were going to be used then I wouldn't be using a variadic template since it wouldn't be necessary. But since I don't, how can I fix this? Am I doing something wrong, is this a compiler bug, or what exactly is going on here?
Note:
For reference, I'm compiling with GCC version 6.3.0 with MinGW on Windows 10.
arg.template target<int(*)(Args...)>(
You need to disambiguate when the std function type is dependent on template args.
C++ doesn't know arg.target is a template when parsing your template function prior to the function being called. And it has to parse it before it is called; this isn't a macro.
So whenever you name a type in a context dependent on your template arguments, or instantiate a template in a context dependent on your template args, you have to tell the parser.
I am a avid emacs user, and want to use sgml markup check routine.
I was naturally headed towards nsgmls, and downloded the source code to compile it.
However, there was a strange error coming from the compiler with the followings.
./../include/RangeMap.h:57: error: type ‘Vector<RangeMapRange<From, To> >’ is not deri ved from type ‘RangeMapIter<From, To>’
./../include/RangeMap.h:57: error: expected ‘;’ before ‘ptr_’
./../include/RangeMap.h: In member function ‘Boolean RangeMapIter<From, To>::next(From&, From&, To&)’:
./../include/RangeMap.h:47: error: ‘ptr_’ was not declared in this scope
I know that some times compiler gets disgruntled by template and typename madness, however the codes seems to have already used typename correctly within the code.
Here are the cope snippets that arouses these errors.
template<class From, class To>
class RangeMapIter {
public:
RangeMapIter(const RangeMap<From,To> &map);
Boolean next(From &fromMin, From &fromMax, To &toMin) {
if (!count_)
return 0;
else {
fromMin = ptr_->fromMin;
fromMax = ptr_->fromMax;
toMin = ptr_->toMin;
ptr_++;
count_--;
return 1;
}
}
private:
size_t count_;
typename Vector<RangeMapRange<From,To> >::const_iterator ptr_;
};
Can anybody help me hash out those errors?
This error message is given by GCC in the wrong order of both type names. (but it apparently fixed this in the latest version). It is meant to say that Vector<RangeMapRange<From,To> >::const_iterator was not found to be a type name. The underlying cause of this diagnostic is that the code is parsed as an access-declaration, which has the following syntax
::[opt] nested-name-specifier template[opt] unqualified-id ;
An example of that syntax
struct A {
int a;
};
struct B : A {
// equivalent to: using A::a;
A::a;
};
In C++11 this access-declaration construct was taken out of the specification and it was deprecated in C++03. But since the compiler still supports parsing it, when the Vector<RangeMapRange<From,To> >::const_iterator is not found to be a type, it will be taken as a name to be declared in an access-declaration (so the parser moves forward across the type specifier section). Hence according to the above syntax, after the unqualified-id which in this case is const_iterator (and in my example was a), it wants to see a semicolon and it wants that Vector<RangeMapRange<From, To> > is a base class of RangeMapIter<From, To>, but confusingly the diagnostic it gives has it the other way around.
Check your names and make sure the type exists.
#include <list>
#include <boost/tuple/tuple.hpp>
template<class InputIterator>
void f(InputIterator it)
{
typedef boost::tuple<typename InputIterator::value_type, int> Pair;
std::list<Pair> paired;
typename std::list<Pair>::const_iterator output;
for(output=paired.begin(); output!=paired.end(); ++output)
{
output->get<1>();
}
}
I'm getting libraries with this template function. Gcc 4.1.2 (codepad.org) reports the following error:
In function 'void f(InputIterator)':
Line 12: error: expected primary-expression before ')' token
compilation terminated due to -Wfatal-errors.
Could someone more experienced with templates offer advice? Either the problem or key phrases to research myself? This has me stuck.
Because get is a function template and the type of output is dependent upon the template parameter InputIterator, you need to use the template keyword:
output->template get<1>();
The Comeau C++ Template FAQ has a good description of why this is necessary.
This question already has answers here:
Closed 12 years ago.
Possible Duplicate:
Why do I need to use typedef typename in g++ but not VS?
Hi, recently I accounted with a "simple problem" of porting code from VC++ to gcc/intel.
The code is compiles w/o error on VC++:
#include <vector>
using std::vector;
template <class T>
void test_vec( std::vector<T> &vec)
{
typedef std::vector<T> M;
/*==> add here typename*/ M::iterator ib=vec.begin(),ie=vec.end();
};
int main()
{
vector<double> x(100, 10);
test_vec<double>(x);
return 0;
}
then with g++ we have some unclear errors:
g++ t.cpp
t.cpp: In function 'void test_vec(std::vector<T, std::allocator<_CharT> >&)':
t.cpp:13: error: expected `;' before 'ie'
t.cpp: In function 'void test_vec(std::vector<T, std::allocator<_CharT> >&) [with T = double]':
t.cpp:18: instantiated from here
t.cpp:12: error: dependent-name 'std::M::iterator' is parsed as a non-type, but instantiation yields a type
t.cpp:12: note: say 'typename std::M::iterator' if a type is meant
If we add typename before iterator the code will compile w/o pb.
If it is possible to make a compiler which can understand the code written in the more "natural way", then for me is unclear why we should add typename? Which rules of "C++ standards"(if there are some) will be broken if we allow all compilers to use without "typename"?
kind regards
Arman.
Here is a page that explains typename.
http://msdn.microsoft.com/en-us/library/8y88s595(VS.71).aspx
This will help you..