Reputation: 69
Consider the following code:
template <typename T>
struct X
{
void foo(){}
};
class Y { };
template <typename T, typename... U>
class Example {
protected:
template <template<typename> typename example_t>
using alias = X<example_t<T>>;
};
template <typename T>
struct ExampleA : public Example<T, Y>
{
using MyAlias = ExampleA::alias<ExampleA>;
};
In C++14 I could do the following and have it work as expected:
ExampleA<int>::MyAlias test;
test.foo();
A recent upgrade to C++17 now gives a warning 'ExampleA<T>::alias': dependent name is not a type
as well as syntax error: identifier 'alias'
.
Normally when you get something involving a dependent name
it means you need to add the typename
keyword as in the following example (iterator
is dependent upon std::vector<T>
):
template<typename T>
void bar() {
/* typename */ std::vector<T>::iterator it;
}
However, I don't believe that to be the case here. Also, using using MyAlias = Example<T, Y>::alias<ExampleA>;
results in the same error.
Did a change in C++17 invalidate this code, or is this a compiler bug? What can I do to fix this in C++17?
Upvotes: 3
Views: 381
Reputation: 41770
MSVC ignored the abscence of desambiguators due to an implementation detail of their compiler.
With new advances and reengineering of their compiler, they now implement two phase name lookup as they should. However, with that implemented, it's really hard in some cases to ignore absence of desambiguators.
They became even more strict with the /permissive-
flag, which is an attempt to disable most of their extensions due to their previous lack of two phase name lookup.
Your code snippet look like this with desambiguators:
template <typename T>
struct ExampleA : public Example<T, Y>
{
using MyAlias = typename ExampleA::template alias<ExampleA>;
};
See it as an opportunity to upgrade the compilance and portability of your code.
However with C++20, many cases where desambigurator were needed are now optional:
template<typename T>
auto wrapper() -> T::type; // no typename!
Upvotes: 7