I want to create a template as follows. I want to delete a list of items from vector vec1
. And the indexes of the items I want to delete are stored in index_list
.
#include <vector>
using namespace std;
template <typename a_type>
bool vector_remove(vector< a_type > & vec1, vector< int > index_list)
{
//index_list is sorted in order from small to large.
if(index_list.size() > vec1.size())
{
cout << "ERROR in 'vector_remove()': index_list is longer than vec1."<<endl;
return false;
}
if(index_list.size() == vec1.size())
{
vec1.clear();
return true;
}
vector< int >::iterator ind_pt = index_list.begin();
vector< a_type >::iterator vec1_pre = vec1.begin();
vector< a_type >::iterator vec1_pos = vec1.begin();
int vec1_ind = 0;
while(ind_pt != index_list.end() && vec1_pos != vec1.end())
{
if(*ind_pt == vec1_ind)
{
ind_pt ++;
vec1_pos ++;
vec1_ind ++;
}
else if( *ind_pt > vec1_ind )
{
*(vec1_pre) = *(vec1_pos);
vec1_pos ++;
vec1_pre ++;
vec1_ind ++;
}
else
{
cout << "ERROR in 'vector_remove'." <<endl;
return false;
}
}
while(vec1_pos != vec1.end())
{
*(vec1_pre) = *(vec1_pos);
vec1_pos ++;
vec1_pre ++;
}
// the above codes are to put all the rejected elements to the end of the vec1.
// pop back all the rejected elements.
while(vec1_pre != vec1.end() )
{
vec1.pop_back();
}
return true;
}
But it returns a lot of errors:
In file included from demo.cpp:3:0:
my_vector.h: In function ‘bool vector_remove(std::vector<a_type>&, std::vector<int>)’:
my_vector.h:21:2: error: need ‘typename’ before ‘std::vector<a_type>::iterator’ because ‘std::vector<a_type>’ is a dependent scope
vector< a_type >::iterator vec1_pre = vec1.begin();
^
my_vector.h:21:29: error: expected ‘;’ before ‘vec1_pre’
vector< a_type >::iterator vec1_pre = vec1.begin();
^
my_vector.h:22:2: error: need ‘typename’ before ‘std::vector<a_type>::iterator’ because ‘std::vector<a_type>’ is a dependent scope
vector< a_type >::iterator vec1_pos = vec1.begin();
^
my_vector.h:22:29: error: expected ‘;’ before ‘vec1_pos’
vector< a_type >::iterator vec1_pos = vec1.begin();
^
my_vector.h:24:38: error: ‘vec1_pos’ was not declared in this scope
while(ind_pt != index_list.end() && vec1_pos != vec1.end())
^
my_vector.h:34:6: error: ‘vec1_pre’ was not declared in this scope
*(vec1_pre) = *(vec1_pos);
^
my_vector.h:45:8: error: ‘vec1_pos’ was not declared in this scope
while(vec1_pos != vec1.end())
^
my_vector.h:47:5: error: ‘vec1_pre’ was not declared in this scope
*(vec1_pre) = *(vec1_pos);
^
my_vector.h:54:8: error: ‘vec1_pre’ was not declared in this scope
while(vec1_pre != vec1.end() )
could anyone help me solve this?
- Forum
- Beginners
- Erro: Need typename because vector<type>
Erro: Need typename because vector<type> is a dependent scope
I am writing a class for a priority vector, but I am facing trouble when I declare an iterator with <type> which is the typename of my class template. The error is in line 37.
error: need ‘typename’ before ‘std::vector<type>::iterator’ because ‘std::vector<type>’ is a dependent scope|
|
|
The error is pretty clear. You need to use typename to tell the compiler that vector<type>::iterator is a type, otherwise the compiler will assume it’s a variable or function.
|
|
Last edited on
Yeah, but why does it need that? Type was already declared at the template.
Topic archived. No new replies allowed.
Содержание
- Error need typename before
- When and why the template & typename keywords are needed
- Template Keyword
- Typename Keyword
- who am i
- what is this
- Error need typename before
- Error need typename before
- Error need typename before
Error need typename before
тебе же русским языком говорят
I invented the term Object-Oriented, and I can tell you I did not have C++ in mind. (c)Alan Kay
My other car is cdr.
Q: Whats the object-oriented way to become wealthy?
A: Inheritance
Ага) Думал, что под ‘typename’ подразумевается ‘Summable’. В голову не пришло, что ‘typename’ надо написать
В книжке «Programming — C++ — C++ by dissection — Standard template library (STL) A tutorial.pdf» написано без ‘typename’. Ошибочка, видимо
Тааа это обычная компилятор-раздолбайство.
Гцц обычно всегда все надо. Он у нас типа строгий. Усе типа как положено!
В студии не то, что бы на стандарт наложено. просто она умная, и очень хорошо понимает желания программиста.
Не требует лишних глупых телодвижений.
В книжке «Programming — C++ — C++ by dissection — Standard template library (STL) A tutorial.pdf» написано без ‘typename’. Ошибочка, видимо
Сие по теме. Не веришь — компиль пример из книги в студии.
Отрокам на ус — есть стандарт, и есть студия. Дабы не растерялись из-за километровых ошибок, что сопутствуют шаблончикам, как мухи навозу.
К тому же я не люблю студию. из-за слишком уж тупой сборки.
Не осилил покамест условную сборку под виндой. От того и маюсь нынче.
Как сделать: если некоторый дефайн (или какая то херь в ключе компиля)
вкл — включить в сборку такие то файлы cpp.
Источник
When and why the template & typename keywords are needed
When working with C++ templates you’ll likely be familiar with the template and typename keywords in the context of template declarations, for example:
However, there are two other contexts where it is necessary to use the template and typename keywords, which often cause confusion at first sight. This post aims to demystify these cases, explaining when and why they are needed.
Template Keyword
Consider the following code example:
At first glance this code looks correct, however, when you compile this you will get an error that looks something like:
error: expected primary-expression before ‘float’
Being faced with this error message it may not be clear what the problem is. The reason for the error can actually be found in two-phase name lookup; the rule that every template is compiled in two phases, firstly for general syntax and again once any dependent names (names that depend on a template parameter) are known. More specifically, due to a grammar ambiguity in C++; being that the token in an expresion such as f.bar () can be parsed either as the start of a template argument list of a call to a member function template specialisation or as a less than operator, the compiler is not able to differentiate until the type of f is known.
This means that in a case such as this when f is a dependent type; foo , the compiler does not yet know what type f is, so the . operator is unable to lookup bar and the compiler treats it purely syntactically as a field of foo so the following is therefore interpreted as a less than operator. In order to instruct the compiler that this is, in fact, a call to a member function template specialisation it is necessary to add the template keyword immediately after the . operator:
This same rule is also applied to the pointer operator and to nested name qualifiers:
An interesting case for this is where you have to use the template keyword even when it involves the this pointer:
This might seem odd, but there are cases due to inheritance where the full type of the this pointer cannot be known until the class template is specialised, such as when the type has a dependant base class.
For those interested in the C++ standardese, the section which describes this rule is as follows:
$14.2/4: When the name of a member template specialization appears after . or -> in a postfix-expression, or after nested-name-specifier in a qualified-id, and the postfix-expression or qualified-id explicitly depends on a template-parameter (14.6.2), the member template name must be prefixed by the keyword template. Otherwise the name is assumed to name a non-template.
Typename Keyword
Take another code example:
If you were to compile this code as it is, you would get an error for the line using t = type_or_value ::tv; something like:
error: need ‘typename’ before ‘type_or_value ::tv’ because ‘type_or_value ‘ is a dependent scope
This error is better than the previous one as it tells you what to do, essentially add the typename keyword immediately before the expression. But why is this necessary? Again the reason for this can be found in the two-phase name lookup.
When the compiler parses code like this involving a dependant type, in this case, type_or_value it cannot know whether the member tv resolves to a type or a non-type and assumes the latter. In order to instruct the compiler that tv is, in fact, resolves to a type it is necessary to add the typename keyword immediately before the expression:
However now that this keyword is there the compiler assumes that the expression will always resolve to a type, so if a later instantiation were to not conform to this, the compiler would through an error. For example:
This would result in an error like:
error: no type named ‘tv’ in ‘struct type_or_value ‘
The typename keyword is not only needed in this case, it’s needed anywhere an unknown member exists in a context where either a type or a non-type is valid. For example:
who am i
I am a software developer at Codeplay Software, where I work on SYCL; an open standard C++ programming model for heterogeneous systems. I am an active contributor to the SYCL and the C++ standards. I am a C++ and game dev enthusiast.
what is this
This is a programming blog about C++, gamedev, and heterogeneous computing.
Источник
Error need typename before
I’m trying to make a silly function to show the content of maps as follows:
However, I got this error in the ‘for’ line: «error: expected ‘;’ before ‘it’» (and then errors that it is not declared, etc). I’m sure that there is no missing ; in other functions. If you try to write a random line before that you get no error there for example, always in the for.
It is there something that you need to do with iterators when you declare generic datatypes?
Apart from that
gcc wrote: |
---|
In function ‘void show_map(const std::map&)’: error: need ‘typename’ before ‘std::map::iterator’ because ‘std::map’ is a dependent scope |
clang wrote: |
---|
error: missing ‘typename’ prior to dependent type name ‘std::map::iterator’ |
So it should be for ( typename std::map::const_iterator it = src.begin();
or, avoid the mess with:
for ( auto it = src.begin(); .
Or maybe go with the range-based for loop:
auto is definitely a friend to you wherever templates are involved.
Источник
Error need typename before
Okay, so here is my updated header file
And here is my updated .cpp file
Your suggestions have cut down my number of errors, so thank you. But Im still getting this one error for line 7 in my .cpp file
error: need ‘typename’ before ‘Ntree ::node’ because ‘Ntree ‘ is a dependent scope.
Apparently there is something wrong with my return type. Any help on this?
So I literally had to write the word ‘typename’ before my return type on line 7. That fixed the issue (but now I am dealing with other errors). Can anyone explain why this works? I’ve never had to do this before.
> error: need ‘typename’ before ‘Ntree ::node’ because ‘Ntree ‘ is a dependent scope.
You may want to read: ‘Why can’t I separate the definition of my templates class from its declaration and put it inside a .cpp file?’ in https://isocpp.org/wiki/faq/templates
So I have to move all my function definitions into my header file? And remove my .cpp file altogether?
Need help serializing this N-ary tree into a file.
The function call in main looks like this: tree.serialize( «foodtree.out» );
I stored the N children of the tree in a vector called ‘children’. Even though I declared ‘children’ publicly in a struct within the class, my compiler says it is not within scope when I try to use it in my serialize and serializeRec function. Any idea why this is happening?
Here is my .h file:
I have made some progress but still have a few bugs to fix. I am still trying to make my serialize function, so please focus on that.
Here is my main (given by professor)
Here is my .h file (made by me):
Take a look at some comments I put in here.
My serialize function works, in that it prints out what is expected, however, I get a «program.exe. has stopped working» message pop up. So It seems my program crashed after printing the tree.
Here is my output:
Any idea why my program crashes even though the function seems to work?
In your main, at the very end, I see that you commented out the call to deserialize(), but you did not comment out assert() function, which if you take a look is actually an #include .h file. I am guessing your professor will use that file to check your work? The program seems to work fine if you comment it out for testing.
I would suggest adding in your deserialize funtion, then leave assert() commented out and test to see what happens.
I figured that was it so I made my deserialize function. I’ve also made my toString function.
However, my assert still seems to fail, and my toString is not working at all:
I’ve commented out my assertion in main(we’ll deal with that later). Right now, my call toString() is giving me an error in main, saying no match for ‘operator Last edited on
Источник
Error need typename before
The problem is that I’m giving a value to a cv-qualifier, so I either have to make a copy of it, or pass it by value. But I’m not allowed to change anything in the code, so I’m kinda having some real trouble with the situation. Could anyone help me out? I’ve been at this for weeks. I didn’t post the whole code to keep it easy to read, but if you need it, let me know and I’ll post it up. But here is the snippet with the source of the error:
Line 4: anEntry is described as const. Therefore you can’t assign anything to it.
Line 4: You’re subscripting out of bounds. if items has 10 entries, those items are 0-9.
Line 5: You have no guarantee that size() items are allocated. If you’re trying to add an item here, you need to do items.push_back(temp)
Line 6: What’s the point of popping the item you just added?
Is the purpose of remove to remove a specific entry (anEntry)? If so, don’t you need to search the vector for the matching entry?
This function is not designed to add anything to the vector. Its supposed to swap the last item in items , which items.size() points to, with anEntry , and once anEntry becomes the final entry in the vector, items.pop_back() removes it.
> Line 4: anEntry is described as const. Therefore you can’t assign anything to it.
Right. So how would I go about dealing with that?
> Line 4: You’re subscripting out of bounds. if items has 10 entries, those items are 0-9.
I’m confused. Are you saying that items.size() is items 0 — 9 ?
> Is the purpose of remove to remove a specific entry (anEntry)? If so, don’t you need to search the vector for the matching entry?
You’re right about, I’ll go ahead and fix up the code. Meantime, how would I pass by value here or make a copy of the cv-qualifier variable?
the last item in items, which items.size() points to
No. items[items.size()] is out of bounds.
As I said before, if size is 10, then the valid entries are 0 — 9. items[10] is not valid.
I’m not understanding why you’re trying to swap something into anEntry. If you can’t change the function declaration, then it would seem that was not the intent.
Are you saying that items.size() is items 0 — 9 ?
Yes. Arrays and vectors in C++ are numbered from 0. Therefore, valid entries are 0 — 9.
how would I pass by value here
I thought you said you can’t change the declaration, which is what you would have to do to pass by value. In any case, I’m not sure that’s what you want to do.
or make a copy of the cv-qualifier variable?
temp is in fact a copy of anEntry, but I’m guessing that you don’t need that.
Its supposed to swap the last item in items, which items.size() points to, with anEntry, and once anEntry becomes the final entry in the vector, items.pop_back() removes it.
I’m sorry, but that makes no sense to me given that anEntry is const. What is the point of making anEntry the final entry in the vector, only to pop it?
It makes a lot more sense to me that your remove function would search the vector to find an entry that matches anEntry. A simple for loop would work for this assuming ItemType has an equality operator. If a matching entry is not found, return false. If a matching entry is found, there use items.erase() to get rid of the entry you found.
oh, I get what you’re saying about the items.size() business now, thanks for clearing all that up. I can’t believe I missed something so obvious.
anyways, here’s what I got when I changed it up to find the index of anEntry and erase it:
and the error message now:
I don’t understand why it’s saying that, when I did at the top.
Don’t you just love error messages involving templates? 🙂
What that cryptic message message is trying to tell you is that std::vector does not have an erase function that takes an item by value, which is what you specified at line 5. erase requires an iterator, not a value type.
There is also a problem with your while loop. What happens if anEntry is not in the vector? You have no condition to exit out of the loop when you reach the end of the vector. This was why I suggested a for loop.
Consider the following:
I tried putting that into my code, and what do you know. more error messages lol. I tried changing it up to make it work, but my attempts didn’t work either so I just reverted it back to what you wrote. Here’s what I got:
Since you didn’t post vectorbag.h, I was uncertain of the type of items, nor could I compile the code I posted to check for errors.
Line 6 should be an iterator of whatever type items is.
Assuming items is: vector items; then line 6 should be:
If items is some type other than vector then you need to adjust the iterator accordingly.
Sorry for the confusion.
I’m still getting errors, I don’t know why.
Источник
When working with C++ templates you’ll likely be familiar with the template
and typename
keywords in the context of template declarations, for example:
template <typename T>
void foo(T t);
However, there are two other contexts where it is necessary to use the template
and typename
keywords, which often cause confusion at first sight. This post aims to demystify these cases, explaining when and why they are needed.
Template Keyword
Consider the following code example:
template <typename T>
struct foo {
template <typename U>
void bar() { }
};
template <typename T>
void func(foo<T> f) {
f.bar<float>();
}
At first glance this code looks correct, however, when you compile this you will get an error that looks something like:
error: expected primary-expression before ‘float’
Being faced with this error message it may not be clear what the problem is. The reason for the error can actually be found in two-phase name lookup; the rule that every template is compiled in two phases, firstly for general syntax and again once any dependent names (names that depend on a template parameter) are known. More specifically, due to a grammar ambiguity in C++; being that the <
token in an expresion such as f.bar<float>()
can be parsed either as the start of a template argument list of a call to a member function template specialisation or as a less than operator, the compiler is not able to differentiate until the type of f
is known.
This means that in a case such as this when f
is a dependent type; foo<T>
, the compiler does not yet know what type f
is, so the .
operator is unable to lookup bar
and the compiler treats it purely syntactically as a field of foo<T>
so the following <
is therefore interpreted as a less than operator. In order to instruct the compiler that this is, in fact, a call to a member function template specialisation it is necessary to add the template
keyword immediately after the .
operator:
template <typename T>
struct foo {
template <typename U>
void bar() { }
};
template <typename T>
void func(foo<T> f) {
f.template bar<float>();
}
This same rule is also applied to the pointer operator and to nested name qualifiers:
template <typename T>
struct foo {
template <typename U>
void bar() { }
};
template <typename T>
void func(foo<T> *fp) {
fp->template bar<float>();
}
template <typename T>
struct foo {
template <typename U>
static void bar() { }
};
template <typename T>
void func() {
foo<T>::template bar<float>();
}
An interesting case for this is where you have to use the template
keyword even when it involves the this pointer:
template <typename T>
struct foo_base {
template <typename U>
void base_bar() {
}
};
template <typename T>
struct foo : public foo_base<T> {
template <typename U>
void bar() {
this->template base_bar<U>();
}
};
This might seem odd, but there are cases due to inheritance where the full type of the this pointer cannot be known until the class template is specialised, such as when the type has a dependant base class.
For those interested in the C++ standardese, the section which describes this rule is as follows:
$14.2/4:
When the name of a member template specialization appears after . or -> in a postfix-expression, or after nested-name-specifier in a qualified-id, and the postfix-expression or qualified-id explicitly depends on a template-parameter (14.6.2), the member template name must be prefixed by the keyword template. Otherwise the name is assumed to name a non-template.
Typename Keyword
Take another code example:
template <typename T>
struct type_or_value;
template <>
struct type_or_value<int> {
static const bool tv = true;
};
template <>
struct type_or_value<float> {
using tv = float;
};
template <typename T>
void func() {
using t = type_or_value<T>::tv;
bool v = type_or_value<T>::tv;
}
If you were to compile this code as it is, you would get an error for the line using t = type_or_value<T>::tv;
something like:
error: need ‘typename’ before ‘type_or_value::tv’ because ‘type_or_value’ is a dependent scope
This error is better than the previous one as it tells you what to do, essentially add the typename
keyword immediately before the expression. But why is this necessary? Again the reason for this can be found in the two-phase name lookup.
When the compiler parses code like this involving a dependant type, in this case, type_or_value<T>
it cannot know whether the member tv
resolves to a type or a non-type and assumes the latter. In order to instruct the compiler that tv
is, in fact, resolves to a type it is necessary to add the typename
keyword immediately before the expression:
template <typename T>
struct type_or_value;
template <>
struct type_or_value<int> {
static const bool tv = true;
};
template <>
struct type_or_value<float> {
using tv = float;
};
template <typename T>
void func() {
using t = typename type_or_value<T>::tv;
bool v = type_or_value<T>::tv;
}
However now that this keyword is there the compiler assumes that the expression will always resolve to a type, so if a later instantiation were to not conform to this, the compiler would through an error. For example:
int main () {
func<int>(f);
}
This would result in an error like:
error: no type named ‘tv’ in ‘struct type_or_value’
The typename
keyword is not only needed in this case, it’s needed anywhere an unknown member exists in a context where either a type or a non-type is valid. For example:
template <typename T>
struct type_or_value;
template <>
struct type_or_value<int> {
static const bool tv = true;
};
template <>
struct type_or_value<float> {
using tv = float;
};
template <typename T>
struct foo {
};
template <typename T>
void func() {
foo<typename type_or_value<T>::tv> f;
}
septe-mber 1 / 1 / 1 Регистрация: 02.01.2013 Сообщений: 123 |
||||
1 |
||||
11.05.2013, 19:58. Показов 2527. Ответов 3 Метки нет (Все метки)
привет всем! почему выскакивает ошибка /home/september/console/tabld_node/dictionary.cpp:93: ошибка: need ‘typename’ before ‘Dictionary<Key, Value>::Node_key’ because ‘Dictionary<Key, Value>’ is a dependent scope …что не так делаю ? объясните пожалуйста
пользуюсь qt creater
__________________
0 |
ForEveR В астрале 8048 / 4805 / 655 Регистрация: 24.06.2010 Сообщений: 10,562 |
||||
11.05.2013, 20:05 |
2 |
|||
septe-mber, need ‘typename’ before ‘Dictionary<Key, Value>::Node_key’ Я просто офигеваю честно говоря. Это трудно в гугл забить? Тут блин ведь даже гугл не нужен…
1 |
… 1804 / 1268 / 935 Регистрация: 12.02.2013 Сообщений: 2,063 |
|
11.05.2013, 20:07 |
3 |
septe-mber, написано же:
need ‘typename’ before ‘Dictionary<Key, Value>::Node_key’ because ‘Dictionary<Key, Value>’ is a dependent scope Нужно поставить typename перед Dictionary<Key, Value>::Node_key
1 |
1 / 1 / 1 Регистрация: 02.01.2013 Сообщений: 123 |
|
11.05.2013, 20:09 [ТС] |
4 |
ForEveR, затупил конкретно…пока перекур делать…
0 |
Anyone dealing with templates will eventually run into something like this
// templated class with a type alias for "type" template <typename T> struct Obj { using type = int; }; template <typename T> void f() { Obj<T>::type var; // should be "int var;" }
But wait, there’s an error on the only statement in f()
# clang-3.6 error: expected ';' after expression Obj<T>::type var; ^ ; # gcc-5.1 error: need ‘typename’ before ‘Obj<T>::type’ because ‘Obj<T>’ is a dependent scope Obj<T>::type var; // should be "int var;"
gcc’s error is great in this case, telling us we need to add a leading typename to make it:
typename Obj<T>::type var;
The leading typename tells the compiler that Obj<T>::type
is a type. But why do we need this? We know that Obj<T>
is a dependent type because it depends on T.
First, you have to realize that without a leading typename, the compiler assumes (in the case of a dependent type) that it’s a static member variable, meaning the following is parsed correctly
template <typename T> struct Obj2 { static constexpr int type = 5; }; template <typename T> void f2() { int n = Obj2<T>::type * 3; }
So what? Why can’t the compiler just look inside of Obj
and see that it has a type
member. Well, in the case of template specializations, it can’t. Consider this:
// general case has "using type = int" template <typename T> struct Obj { using type = int; }; // specialization for int has "int type = 2" template <> struct Obj<int> { static constexpr int type = 2; };
Inside of f()
we don’t know which one of these we’re dealing with. f()
means it’s using the general template, but f()
uses the specialization. The programmer must clarify that they expect a type.
You might be thinking “right, but in this case it’s clear that the body of f()
is declaring a variable.” Right you are, but it’s not always this clear. What if instead we had
int x = 5; // global variable x template <typename T> void f() { Obj<T>::type * x; }
Now we have two possible versions of this
int * x; // declaring a local variable x of type int* 2 * x; // multiplication expression
Both of these lines make sense, but they mean very different things. It’s not always clear which way it should be parsed.
You’re less likely to see this problem, but I think it’s cool and has the same idea behind it. When your dependent name has a templated member function, the compiler gets confused about what you mean again:
struct Obj { template <typename U> void m(); };
Now let’s create a variable with dependent type Obj<T>
and call m()
template <typename T> void f() { Obj<T> v; v.m<int>(); }
But hold on errors! this time clang being more helpful
# gcc-5.1 error: expected primary-expression before ‘int’ v.m<int>(); # clang-3.6 error: use 'template' keyword to treat 'm' as a dependent template name v.m<int>(); ^ template
Huh? template keyword? What’s happening is the compiler doesn’t know that m
is a templated member function, we need tell it
v.template m<int>();
Alright so what’s the alternative here. Well, it’s a pretty well known issue with the C++ grammar that without context, you don’t know what certain lines mean. Borrowed from the D docs, consider the line:
A<B,C>D;
This could mean two things, (1) A is a templated class, B and C are template arguments, and D is a variable declared with that type. for example:
template <typename T, typename U> struct A; using A = int; using B = int; A<B,C> D; // A<int,int> D
Or (2), A, B, C, and D are all variables and this is two comparisons separated by a comma
int A{}, B{}, C{}, D{}; (A < B), (C > D);
So, by default the compiler is assuming that m
is not a template, which means that it assumes the angle brackets are less than and greater than operators, so it’s parsed as
((v.m) < int) > ();
This could make sense in a different context
template <typename T> struct Obj { int m; };
And then the following:
int a{}; v.m<a>0; ((v.m < a) > 0
So the “dot template” is needed to say that what follows is a template. Like I said this is far less common, and the syntax is so awkward that it can drive design decisions. If you’ve ever wondered why std::get
is a free function, a big part is that std::tuple
is often used as a dependent type.
template <typename... Ts> void f(std::tuple<Ts...>& t) { std::get<0>(t); // nice t.template get<0>(); // gross }
Когда я пытаюсь скомпилировать, я получаю следующие ошибки:
In member function 'double search::IDAstar<State, MoveContainer>::dfs(const State&, double)': 153:18: error: need 'typename' before
'MoveContainer:: const_iterator' because 'MoveContainer' is a dependent scope 153:48: error: expected ';' before 'it' 154:17: error: 'it'
was not declared in this scope
In member function '{anonymous}::State& {anonymous}::State::operator=(const {anonymous}::State&)':
234:9: warning: no return statement in function returning non-void [-Wreturn-type] In instantiation of
'double search::IDAstar<State, MoveContainer>::dfs(const State&, double) [with State = {anonymous}::State; MoveContainer = std::list<search::Move<{anonymous}::State> >]':
122:34: required from 'std::list<State> search::IDAstar<State, MoveContainer>::solve(const State&)
[with State = {anonymous}::State; MoveContainer = std::list<search::Move<{anonymous}::State> >]' 371:55: required from here
152:57: error: invalid initialization of non-const reference of type 'std::list<search::Move<{anonymous}::State> >&' from an rvalue of type
'{anonymous}::State::MoveContainer {aka std::list<search::Move<{anonymous}::State> >}' 153:66: error: dependent-name 'MoveContainer:: const_iterator'
is parsed as a non-type, but instantiation yields a type 153:66: note: say 'typename MoveContainer:: const_iterator' if a type is meant
search_IDAstar.h
///////////////////////////////////////////////////////////////////////////////
//
// search_IDAstar.h
//
///////////////////////////////////////////////////////////////////////////////
#ifndef SEARCH_IDASTAR_H
#define SEARCH_IDASTAR_H
#include <list>
#include <limits> // infinity
namespace search
{
// A Move is a generic successor of a State (see IDAstar below).
template<typename State>
class Move
{
public:
// Create a move to the given successor state with the given cost.
Move(const State& s, double g) :
s(s),
g(g)
{
// empty
}
// Destructor
~Move()
{
// empty
}
// Copy constructor
Move(const Move& copy) :
s(copy.s),
g(copy.g)
{
// empty
}
// Assignment operator
Move& operator= (const Move& rhs)
{
s = rhs.s;
g = rhs.g;
}
// Return successor state.
State state() const
{
return s;
}
// Return cost of this move.
double cost() const
{
return g;
}
private:
State s;
double g;
};
// IDAstar is a generic implementation of the IDA* search algorithm.
//
// Instances of the parameter State should implement the following methods:
//
// double State::h() const;
// bool State::isGoal() const;
// MoveContainer State::successors(std::list<State>& solution) const;
//
// where h() is an admissible heuristic, isGoal() returns true iff the
// state is a goal state, and successors() returns a container of moves,
// each of which implements the following methods:
//
// State state() const;
// double cost() const;
//
// where state() is a successor state and cost() is the cost of the
// corresponding move. The successors() method may exclude cycles using
// the given partial solution sequence of states.
template<typename State, typename MoveContainer = std::list<Move<State> > >
class IDAstar
{
public:
// Constructor
IDAstar() :
solution(),
solved(false),
fLimit(0),
inf(std::numeric_limits<double>::infinity())
{
// empty
}
// Destructor
~IDAstar()
{
// empty
}
// Use IDA* search to find an optimal path from the given state to a
// goal state. Return a list of states from the given state to the
// goal state, or an empty list if no solution exists.
std::list<State> solve(const State& s)
{
solution.clear();
solved = false;
fLimit = s.h();
while (!solved && fLimit < inf)
{
fLimit = dfs(s, 0);
}
return solution;
}
private:
// Private unimplemented copy constructor and assignment operator
IDAstar(const IDAstar& copy);
IDAstar& operator= (const IDAstar& rhs);
std::list<State> solution;
bool solved;
double fLimit;
double inf;
double dfs(const State& s, double g)
{
double f = g + s.h();
if (f > fLimit)
{
return f;
}
solution.push_back(s);
if (s.isGoal())
{
solved = true;
return f;
}
double fMin = inf;
MoveContainer& moves = s.successors(solution);
for (MoveContainer::const_iterator it = moves.begin();
it != moves.end(); ++it)
{
f = dfs(it->state(), g + it->cost());
if (solved)
{
return f;
}
if (f < fMin)
{
fMin = f;
}
}
solution.pop_back();
return fMin;
}
};
} // namespace search
#endif
tiles.cpp
///////////////////////////////////////////////////////////////////////////////
//
// tiles.cpp
//
///////////////////////////////////////////////////////////////////////////////
#include "search_IDAstar.h"#include <vector>
#include <algorithm> // find
#include <cstdlib> // abs
#include <iostream>
#include <ctime>
namespace // unnamed namespace
{
// Number of rows/columns in the sliding tile puzzle.
const int rows = 4;
const int columns = 4;
const int size = rows*columns;
// Manhattan distance heuristic.
int manhattan[size][size];
// A State is a configuration of a sliding tile puzzle.
class State
{
public:
// A state may be specified as a vector, where tiles[i] is the tile in
// the i-th position in row-major order, and the blank is specified as
// rows*columns == size == tiles.size().
typedef std::vector<int> Tiles;
// Constructor
State(const Tiles& tiles) :
tiles(tiles),
blank(0)
{
for (int i = 0; i < size; ++i)
{
if (tiles[i] == size)
{
blank = i;
break;
}
}
}
// Destructor
~State()
{
// empty
}
// Copy constructor
State(const State& copy) :
tiles(copy.tiles),
blank(copy.blank)
{
// empty
}
// Assignment operator
State& operator= (const State& rhs)
{
tiles = rhs.tiles;
blank = rhs.blank;
}
// Equality operator
bool operator== (const State& rhs)
{
for (int i = 0; i < size; ++i)
{
if (tiles[i] != rhs.tiles[i])
{
return false;
}
}
return true;
}
// Return admissible heuristic.
double h() const
{
int cost = 0;
for (int i = 0; i < size; ++i)
{
if (i != blank)
{
cost += manhattan[i][tiles[i] - 1];
}
}
return cost;
}
// Return true iff this state is a goal state.
bool isGoal() const
{
for (int i = 0; i < size; ++i)
{
if (tiles[i] != i + 1)
{
return false;
}
}
return true;
}
// Return successors of this state.
typedef search::Move<State> Move;
typedef std::list<Move> MoveContainer;
MoveContainer successors(std::list<State>& solution) const
{
MoveContainer moves;
// Move blank right.
if ((blank + 1)%columns != 0)
{
State s(*this);
s.tiles[blank] = tiles[blank + 1];
s.tiles[blank + 1] = size;
s.blank = blank + 1;
if (std::find(solution.begin(), solution.end(), s) ==
solution.end())
{
moves.push_back(Move(s, 1));
}
}
// Move blank up.
if (blank - columns >= 0)
{
State s(*this);
s.tiles[blank] = tiles[blank - columns];
s.tiles[blank - columns] = size;
s.blank = blank - columns;
if (std::find(solution.begin(), solution.end(), s) ==
solution.end())
{
moves.push_back(Move(s, 1));
}
}
// Move blank left.
if (blank%columns != 0)
{
State s(*this);
s.tiles[blank] = tiles[blank - 1];
s.tiles[blank - 1] = size;
s.blank = blank - 1;
if (std::find(solution.begin(), solution.end(), s) ==
solution.end())
{
moves.push_back(Move(s, 1));
}
}
// Move blank down.
if (blank + columns < size)
{
State s(*this);
s.tiles[blank] = tiles[blank + columns];
s.tiles[blank + columns] = size;
s.blank = blank + columns;
if (std::find(solution.begin(), solution.end(), s) ==
solution.end())
{
moves.push_back(Move(s, 1));
}
}
return moves;
}
Tiles tiles;
int blank;
};
} // unnamed namespace
int main()
{
// Initialize pre-computed Manhattan distance heuristic.
for (int i = 0; i < size; ++i)
{
for (int j = 0; j < size; ++j)
{
manhattan[i][j] = std::abs(i/columns - j/columns) +
std::abs(i%columns - j%columns);
}
}
// Get starting puzzle configuration.
std::cout << "Enter puzzle: ";
State::Tiles tiles;
for (int i = 0; i < size; ++i)
{
int t;
std::cin >> t;
tiles.push_back(t);
}
// Search for a solution.
search::IDAstar<State> ida;
std::clock_t tic = std::clock();
std::list<State> solution = ida.solve(State(tiles));
std::clock_t toc = std::clock();
// Display solution.
std::cout << "Solution in " << static_cast<int>(solution.size()) - 1 <<
" moves." << std::endl;
for (std::list<State>::iterator it = solution.begin(); it != solution.end(); ++it)
{
State::Tiles& tiles = (*it).tiles;
for (size_t i = 0; i < tiles.size(); ++i)
{
std::cout << tiles[i] << " ";
}
std::cout << std::endl;
}
std::cout << "Elapsed time = " <<
static_cast<double>(toc - tic)/CLOCKS_PER_SEC << " seconds." <<
std::endl;
}
Первая ошибка MoveContainer :: const_iterator я набрал auto, и это было временное исправление. Сначала я думаю, что это проблема с пространством имен или iostream, но это не так. Я компилирую с C ++ 11, C ++ 14 в Linux. Программа является примером алгоритма IDA * для решения 15 головоломок.
0
Решение
153:18: error: need 'typename' before 'MoveContainer:: const_iterator'
because 'MoveContainer' is a dependent scope
Этот говорит вам, что делать. + Изменить
for (MoveContainer::const_iterator it = moves.begin();
в
for (typename MoveContainer::const_iterator it = moves.begin();
Увидеть Где и почему я должен поставить «шаблон» а также «имяТипа» ключевые слова?
234:9: warning: no return statement in function returning non-void
Как говорится, ваш State::operator=
отсутствует ответное заявление.
// Assignment operator
State& operator= (const State& rhs)
{
tiles = rhs.tiles;
blank = rhs.blank;
return *this;
}
Или лучше не определять operator=
вообще, по правилу нуля.
52:57: error: invalid initialization of non-const reference of type
'std::list<search::Move<{anonymous}::State> >&' from an rvalue of type
'{anonymous}::State::MoveContainer {aka
std::list<search::Move<{anonymous}::State> >}'
Прямо здесь:
MoveContainer& moves = s.successors(solution);
Вы пытаетесь инициализировать ссылку из функции, которая возвращает значение. Бросьте ссылку:
MoveContainer moves = s.successors(solution);
1
Другие решения
В шаблонах с ++, зависимые имена предполагается, что они являются значениями / функциями и могут быть проанализированы только как имя типа или шаблон, если вы явно указали его, используя ключевые слова типа или типа.
В этом случае, MoveContainer::const_iterator
это имя, которое зависит от параметра шаблона MoveContainer
, поэтому вам нужно сообщить компилятору, что это имя типа:
for (typename MoveContainer::const_iterator it = moves.begin();
it != moves.end(); ++it)
{
//...
}
Для получения дополнительной информации о том, почему это необходимо, см. этот ответ.
0
Сообщение об ошибке довольно явно:
error: need 'typename' before
'MoveContainer:: const_iterator' because 'MoveContainer' is a dependent scope
Если вы просто измените код на
for (typename MoveContainer::const_iterator it = moves.begin();
it != moves.end(); ++it)
тогда это должно скомпилироваться.
Причина в том, что для аргументов шаблона, таких как MoveContainer :: const_iterarator, компилятор не может определить, является ли const_iterator типом или статическим членом. Использование ‘typename’ говорит о том, что это тип. Старые компиляторы не были строгими в этом, и вы часто получаете эту ошибку при обновлении до более нового компилятора.
0