iterator of template based container - c++

template<class A,class B>
void tmp(){
set<int,int>::iterator it; //works
set<A,B>::iterator it; // doesn't work
}

Due to some rather annoying limitations in C++'s grammar, you must explicitly tell C++ that set<A,B>::iterator is a type name, rather than a static member identifier, using the typename keyword. For example, this code compiles just fine:
#include <set>
template<class A, class B>
void tmp() {
std::set<int,int>::iterator x; // OK
typename std::set<A,B>::iterator it; // Also OK
}
int main() {
tmp<int,int>();
return 0;
}
This occurs because C++ requires that the compiler make a final decision as to whether to interpret set<A,B>::iterator as a type or as a variable/function when it's parsing the grammar; before the template is instantiated. However, prior to template instantiation, it is impossible to make that determination, as in the general case this may depend on the values of A and B. As such, the compiler will assume it to be a variable/function unless explicitly stated otherwise. This then results in a parse error.

Related

Why do MSVC and Clang produce different outputs for the same function template call?

After messing around with concepts I came across something in visual studio that I didn't understand, although I don't know if the issue here is anything to do with concepts specifically. I'm sure there's a reason for this behaviour, but it would be great if someone could explain. There are two parts to this question. For the following snippet:
#include <concepts>
#include <utility>
template <typename PolicyType, typename T, typename... Ts>
concept concept_policy = requires(Ts&&... args)
{
{ PolicyType::template Create<T>(args...) } -> std::same_as<T*>;
};
struct basic_policy
{
template <typename T, typename... Ts>
static T* Create(Ts&&... args)
{
return new T { std::forward<Ts>(args)... };
}
};
struct type_a
{
int m_val;
};
template <concept_policy<int> TPolicy = basic_policy>
static void DoSomething()
{
//works on msvc, msvc needs the "template" for no args, but not with?
{
type_a* type1 = TPolicy::Create<type_a>(5); //why is this fine without template?
type_a* type2 = TPolicy::template Create<type_a>(); //why does this require template if the above doesn't?
}
// //clang requires both to have "template"
// {
// type_a* type1 = TPolicy::template Create<type_a>(5);
// type_a* type2 = TPolicy::template Create<type_a>();
// }
}
int main()
{
DoSomething();
{
//both versions compile fine without "template"
basic_policy policy;
type_a* type1 = basic_policy::Create<type_a>(5);
type_a* type2 = basic_policy::Create<type_a>();
}
return 0;
}
Why do msvc and clang produce different outputs here? Msvc is fine having the "template" omitted for the call with arguments, but not without
Using a similar policy design, is there any way around prefixing the Create with "template"? Ideally I'd like to be able to call TPolicy::Create<type>(...);
Clang is correct: the call to TPolicy::Create<type_a> requires the word template because TPolicy is a dependent type.
Specifically, according to the standard, when we have a fragment of the form T::m< where T is a dependent type other the current instantiation, the compiler must assume that < is the less-than operator, not the beginning of a template argument list. If you mean < as a template argument list, then you must prefix m with the keyword template.
This behaviour is specified in [temp.names]/3. A < that doesn't satisfy any of the conditions listed must be interpreted to mean the less-than operator; the compiler cannot use contextual information to determine that it means the beginning of a template argument list.
As for why MSVC sometimes fails to diagnose the violation, I am not sure.
There is no way to make TPolicy::Create<type>(...); just work without the template keyword. If you really hate writing template, you have to restructure your code so that Create is a non-member, sort of like std::get in the standard library (which would have to be invoked in the form .template get<i>() if it were a class member and the object expression were of dependent type). I guess in this case, Create could be a class template that takes the policy class as one of its template arguments, and the type you want to create as another. I have been told that people often do make their templates into non-members for this exact reason (to avoid having to write template). I think that's a big mistake. It's better to write template than to choose a less natural design.

What C++20 change to reverse_iterator is breaking this code?

The following code compiles in C++11, C++14, and C++17, but does not compile in C++20. What change to the standard broke this code?
#include <vector>
#include <utility>
template<typename T>
struct bar
{
typename T::reverse_iterator x;
};
struct foo
{
bar<std::vector<std::pair<foo, foo>*>> x;
};
int main()
{
foo f;
}
The error is quite long, but can be summarized as:
template argument must be a complete class
This was always undefined. [res.on.functions]/2.5 says:
In particular, the effects are undefined in the following cases:
[...]
If an incomplete type ([basic.types]) is used as a template argument when instantiating a template component or evaluating a concept, unless specifically allowed for that component.
std::pair does not (and cannot) support incomplete types. You were just relying on order of instantiation to kind of get around that. Something changed in the library that slightly changed the evaluation order, leading to the error. But undefined behavior is undefined - it happened to work before and it happens to not work now.
As to why it's specifically C++20 that is causing this to fail. In C++20, iterators changed to have this new iterator_concept idea. In order to instantiate that, reverse_iterator needs to determine what the concept should be. That looks like this:
#if __cplusplus > 201703L && __cpp_lib_concepts
using iterator_concept
= conditional_t<random_access_iterator<_Iterator>,
random_access_iterator_tag,
bidirectional_iterator_tag>;
using iterator_category
= __detail::__clamp_iter_cat<typename __traits_type::iterator_category,
random_access_iterator_tag>;
#endif
Now, in the process of checking random_access_iterator, the root of iterator concept hierarchy is wonderfully named input_or_output_iterator, specified in [iterator.concept.iterator]:
template<class I>
concept input_or_output_iterator =
requires(I i) {
{ *i } -> can-reference;
} &&
weakly_incrementable<I>;
So, we have to do *i on our iterator type. That's __gnu_cxx::__normal_iterator<std::pair<foo, foo>**, std::vector<std::pair<foo, foo>*> > , in this case. Now, *i triggers ADL - because of course it does. And ADL requires instantiation of all the associated types - because those associated types might have injected friends that could be candidates!
This, in turn, requires instantiating pair<foo, foo> - because, we have to check. And then that ultimately fails in this specific case because instantiating a type requires instantiating all of the type's special member functions, and the way that libstdc++ implements conditional assignment for std::pair is using Eric Fisellier's trick:
_GLIBCXX20_CONSTEXPR pair&
operator=(typename conditional<
__and_<is_copy_assignable<_T1>,
is_copy_assignable<_T2>>::value,
const pair&, const __nonesuch&>::type __p)
{
first = __p.first;
second = __p.second;
return *this;
}
And is_copy_assignable requires complete types and we don't have one.
But really even if pair used concepts to check in this case, that would still involve instantiating the same type traits, so we'd ultimately end up in the same position.
Moral of the story is, undefined behavior is undefined.

SFINAE to make base template always result in error

So I'm designing a sort of my_numeric_cast function to limit the types of conversions available when using a framework I'm writing.
It was pretty straight forward to do something like
template<typename To, typename From>
constexpr To my_numeric_cast(From);
template<>
constexpr float my_numeric_cast<float, int>(int i) { return i; }
Which works, allowing only casting from ints to floats whenever the cast is used. And producing a linkage error whenever a cast not in the white list is attempted.
However, I'd really want to make this a compilation error, to catch the misuse much faster.
How do I make the base template body valid, expect when instantiating it?
You cannot write a template function specialization for which no template argument makes the body valid in C++. The result if you do so is an ill formed program with no diagnostic required. This includes the primary specialization.
So most of the answers here are simply undefined behaviour. They may work, but they are not valid C++. They may work today, but after a library upgrade a compiler upgrade or a different build target they could fail in completely different and surprising ways. Relying on UB with no strong reason is a bad idea.
On the plus side, we can do away with template specialization and fix your problem in one fell swoop:
template<class T>struct tag_t{}; // may need `constexpr tag_t(){}` on some compilers
template<class T>constexpr tag_t<T> tag{};
template<class T, class F>
constexpr T my_numeric_cast(F, tag_t<F>)=delete; // generates compile time error
constexpr float my_numeric_cast(int i, tag_t<float>) { return i; } // not a template! Could be if you want it to be.
template<typename To, typename From>
constexpr To my_numeric_cast(From f){
return my_numeric_cast(f, tag<To>);
}
and done.
=delete generates friendly messages. Program is well formed. Implementing casts is no longer a specialization. You can even implement it in the namespace of a type being cast to or from as ADL is enabled.
If you solve a problem with template function specialization, reconsider. They are fragile, do not work like class template specialization or function overloading (while looking like both of them!), and usually are not the best solution to anything. There are exceptions when it may be a good idea, but they are quite rare, and given how rare they are avoiding the quirky feature may still be worth it.
You can use traits to get a compile time error:
template<typename, typename> struct RetTraits;
// Enable it for int -> float
template<> struct RetTraits<int, float> { using type = float; };
template<typename To, typename From>
using RetType = typename RetTraits<To, From>::type;
template<typename To, typename From>
constexpr RetType<To, From> my_numeric_cast(From f) {
return To(f);
}
int main() {
my_numeric_cast<int, float>(42);
// This won't compile
// my_numeric_cast<int, int>(42);
}

Why can't you use a Template when iterating

When compiling :
#include <vector>
template<class T> class foo {
void bar() {
std::vector<T> x;
std::vector<T>::iterator i = x.begin();
}
};
int main() {
return 0;
}
I get :
# g++ ~test.cpp
test.cpp: In member function `void foo<T>::bar()':
test.cpp:7: error: expected `;' before "i"
Shouldn't this work?
g++ version 3.4.3 on RHEL.
You can, but you need to tell it that iterator there is a type (it doesn't know, because in general it can depend on T - as vector is a template type, and could in theory have specializations for some T where iterator is a function or something else). So, you have to use typename to indicate that it is always a type:
typename std::vector<T>::iterator i = x.begin();
This should do:
template<class T> class foo {
void bar() {
std::vector<T> x;
typename std::vector<T>::iterator i = x.begin();
}
};
I'll quote the IBM C++ compiler manual:
The typename keyword (C++ only) Use
the keyword typename if you have a
qualified name that refers to a type
and depends on a template parameter.
Only use the keyword typename in
template declarations and definitions.
The following example illustrates the
use of the keyword typename:
template<class T> class A
{
T::x(y);
typedef char C;
A::C d;
}
The statement T::x(y) is ambiguous. It
could be a call to function x() with a
nonlocal argument y, or it could be a
declaration of variable y with type
T::x. C++ will interpret this
statement as a function call. In order
for the compiler to interpret this
statement as a declaration, you would
add the keyword typename to the
beginning of it. The statement A::C d;
is ill-formed. The class A also refers
to A and thus depends on a template
parameter. You must add the keyword
typename to the beginning of this
declaration:
typename A::C d; You can also use
the keyword typename in place of the
keyword class in template parameter
declarations.
In case it isn't clear what the others mean by the compiler not knowing that it's a type: at the point where the compiler parses template foo, it doesn't know that you won't later do:
namespace std {
template<>
class vector<int> {
int iterator(void);
};
}
And then instantiate foo<int>. Then vector<T>::iterator would be a function, not a type, and the relevant line in foo should fail to parse. To work without help, compilers would have to hold off parsing foo until it's instantiated, and they've found the right class to determine whether 'iterator' is a type expression or a value expression. I suspect this could lead to circular dependencies, but would certainly be especially painful to implement. So the standard says that an expression in a template which is dependent on a parameter is assumed not to be a type unless stated to be. There are two (I think) ways to state it to be a type, which are (1) use it as a base class, and (2) qualify it with typename.
OK, so in this example you're actually not allowed to specialize std::vector. And vector actually has more template parameters than just the one I've used. So in your example, the compiler could in theory assume more than it does. But the standard doesn't make special provision for the language to rely on knowledge of what templates are in namespace std, because (1) the intention is that implementations can implement namespace std in normal headers treated the same as any other headers by the compiler, and (2) C++ is supposed to be designed as language+libraries, not as "language with special-case syntax for libraries". In fact, (1) and (2) are sort of the same requirement.

Why do I need to use typedef typename in g++ but not VS?

It had been a while since GCC caught me with this one, but it just happened today. But I've never understood why GCC requires typedef typename within templates, while VS and I guess ICC don't. Is the typedef typename thing a "bug" or an overstrict standard, or something that is left up to the compiler writers?
For those who don't know what I mean here is a sample:
template<typename KEY, typename VALUE>
bool find(const std::map<KEY,VALUE>& container, const KEY& key)
{
std::map<KEY,VALUE>::const_iterator iter = container.find(key);
return iter!=container.end();
}
The above code compiles in VS (and probably in ICC), but fails in GCC because it wants it like this:
template<typename KEY, typename VALUE>
bool find(const std::map<KEY,VALUE>& container, const KEY& key)
{
typedef typename std::map<KEY,VALUE>::const_iterator iterator; //typedef typename
iterator iter = container.find(key);
return iter!=container.end();
}
Note: This is not an actual function I'm using, but just something silly that demonstrates the problem.
The typename is required by the standard. Template compilation requires a two step verification. During the first pass the compiler must verify the template syntax without actually supplying the type substitutions. In this step, std::map::iterator is assumed to be a value. If it does denote a type, the typename keyword is required.
Why is this necessary? Before substituing the actual KEY and VALUE types, the compiler cannot guarantee that the template is not specialized and that the specialization is not redefining the iterator keyword as something else.
You can check it with this code:
class X {};
template <typename T>
struct Test
{
typedef T value;
};
template <>
struct Test<X>
{
static int value;
};
int Test<X>::value = 0;
template <typename T>
void f( T const & )
{
Test<T>::value; // during first pass, Test<T>::value is interpreted as a value
}
int main()
{
f( 5 ); // compilation error
X x; f( x ); // compiles fine f: Test<T>::value is an integer
}
The last call fails with an error indicating that during the first template compilation step of f() Test::value was interpreted as a value but instantiation of the Test<> template with the type X yields a type.
Well, GCC doesn't actually require the typedef -- typename is sufficient. This works:
#include <iostream>
#include <map>
template<typename KEY, typename VALUE>
bool find(const std::map<KEY,VALUE>& container, const KEY& key)
{
typename std::map<KEY,VALUE>::const_iterator iter = container.find(key);
return iter!=container.end();
}
int main() {
std::map<int, int> m;
m[5] = 10;
std::cout << find(m, 5) << std::endl;
std::cout << find(m, 6) << std::endl;
return 0;
}
This is an example of a context sensitive parsing problem. What the line in question means is not apparent from the syntax in this function only -- you need to know whether std::map<KEY,VALUE>::const_iterator is a type or not.
Now, I can't seem to think of an example of what ...::const_iterator might be except a type, that would also not be an error. So I guess the compiler can find out that it has to be a type, but it might be difficult for the poor compiler (writers).
The standard requires the use of typename here, according to litb by section 14.6/3 of the standard.
It looks like VS/ICC supplies the typename keyword wherever it thinks it is required. Note this is a Bad Thing (TM) -- to let the compiler decide what you want. This further complicates the issue by instilling the bad habit of skipping the typename when required and is a portability nightmare. This is definitely not the standard behavior. Try in strict standard mode or Comeau.
This is a bug in the Microsoft C++ compiler - in your example, std::map::iterator might not be a type (you could have specialised std::map on KEY,VALUE so that std::map::iterator was a variable for example).
GCC forces you to write correct code (even though what you meant was obvious), whereas the Microsoft compiler correctly guesses what you meant (even though the code you wrote was incorrect).
It should be noted that the value/type kinding issue is not the fundamental problem. The primary issue is parsing. Consider
template<class T>
void f() { (T::x)(1); }
There is no way to tell if this is a cast or a function call unless the typename keyword is mandatory. In that case, the above code contains a function call. In general the choice cannot be delayed without forgoing parsing altogether, just consider fragment
(a)(b)(c)
In case you didn't remember, cast has a higher precedence than function call in C, one reason Bjarne wanted function style casts. It is therefore not possible to tell if the above means
(a)(b) (c) // a is a typename
or
(a) (b)(c) // a is not a typename , b is
or
(a)(b) (c) // neither a nor b is a typename
where I inserted space to indicate grouping.
Note also "templatename" keyword is required for the same reason as "typename", you can't parse things without knowing their kind in C/C++.