Cannot get templates to compile under Visual Studio and clang - c++

I have the following minified code.
The line with // Only VS compiles on VS but not on clang,
And the line with // Only clang compiles on clang but not on VS.
Who is correct? More importantly, how to make an equivalent line compile on both?
The versions tested are clang 3.7.0, and VS 2015.
#include <functional>
#include <tuple>
template<typename... Args>
class C
{
struct B
{
std::function<void(Args...)> func;
B(std::function<void(Args...)> func) : func(func) { }
};
template<typename T>
struct D : B
{
using B::B;
template<size_t... I>
void Call(T &t, std::index_sequence<I...>)
{
func(std::get<I>(t)...); // Only VS
B::template func(std::get<I>(t)...); // Only clang
}
};
D<std::tuple<Args...>> d;
public:
C(std::function<void(Args...)> func) : d(func) { }
void Call()
{
std::tuple<Args...> t;
d.Call(t, std::make_index_sequence<sizeof...(Args)>());
}
};
void f(int)
{
}
int main()
{
C<int> c(f);
c.Call();
}

I think both are wrong. For the first use func(...) is an unqualified name looked up using argument dependent look-up which doesn't find a function in a base class. The use of B::template func(...) uses an excess keyword template. You can force look-up of func in the context of the class using
this->func(...);
The this-> forces the necessary context. I think, B::func(...) should also work but I'm using this->func(...) in similar situations.
I think the relevant clause is 14.6.2 [temp.dep] paragraph 3:
In the definition of a class or class template, the scope of a dependent base class (14.6.2.1) is not examined during unqualified name lookup either at the point of definition of the class template or member or during an instantiation of the class template or member.
The issue is that B is dependent on the template arguments of the enclosing class. Qualifying the name with this-> or the base class name force look-up in the base class context.

Related

When giving a template parameter a default argument, VS 2017 cannot find previously defined types properly

The following code:
namespace N {
template <typename A, typename B = A>
class Foo;
}
template <typename C, typename D>
class N::Foo {
public:
Foo() = default;
};
int main()
{
N::Foo<char> foo;
}
involves a (forward) declaration of the class template Foo inside namespace N
with two type parameters (A and B). The (forward) declaration gives the second parameter a default value which is identical to the first parameter (A). Later, this class is defined with its parameters differently named (C and D). Since it is already specified, the default is not given.
This compiles in GCC 7.1 and Clang 3.8 (in C++17 mode) except that the unused variable foo is warned. However, VS 2017 15.7.5 (in C++17 mode) says A is undefined identifier, and says it is not a valid type name for parameter D.
To my surprise, when I changed the code into this:
namespace N {
template <typename A, typename B = C> //note: A changed into C
class Foo;
}
template <typename C, typename D>
class N::Foo {
public:
Foo() = default;
};
int main()
{
N::Foo<char> foo;
}
VS accepts it! (It does not compile in GCC or Clang, though)
I think VS is wrong here. It tries to interpret the default argument in a different context (in this specific case, the definition of Foo) whereas GCC and Clang don't. At which step was I wrong? Or is this a bug of VS?
Any help will be appreciated.
(Sorry for my bad English)
I would say that this is definitely a compiler bug. Using the name of a previous template parameter in the default argument of a subsequent parameter is common practice, the standard library itself does it all over the place (e.g., allocators and comparison functions for standard containers). The standard even explicitly mentions this possibility in a note in [basic.scope.temp] §3.
VS 2015 seems to be affected too. Note that the template doesn't even have to be in another namespace. I stripped down your example a bit further:
template <typename A, typename B = A>
struct S;
template <typename C, typename D>
struct S {};
int main()
{
S<int> s;
}
and this seems to already trigger the issue…
Try this.
namespace N {
template <typename A, typename B = A>
class Foo;
}
template <typename A, typename B> //A and B is TYPE
class N::Foo {
public:
Foo() = default;
};
int main()
{
N::Foo<char> foo;
}
You can check the reason in the webpage:https://learn.microsoft.com/en-us/cpp/cpp/templates-cpp
T is a template parameter; the typename keyword says that this
parameter is a placeholder for a type. When the function is called,
the compiler will replace every instance of T with the concrete type
argument that is either specified by the user or deduced by the
compiler.
For example, it must be an error if you write a code like:
double example(double,int);
int main()
{
//...
}
double example(double a,double b)
{
//...
}
because the TYPE you specified conflicts with the prototype.
(Sorry for my poor English)

How does 'using' directive work with template member functions

I am using the CRTP and the base class has a template function. How can I use that member function in a templated derived class?
template <typename T>
struct A {
int f();
template <typename S>
int g();
};
struct B: public A<B> {
int h() { return f() + g<void>(); } // ok
};
template <typename T>
struct C: public A<C<T>> {
// must 'use' to get without qualifying with this->
using A<C<T>>::f; // ok
using A<C<T>>::g; // nope
int h() { return f() + g<void>(); } // doesn't work
};
* Edit *
An earlier question, Using declaration for type-dependent template name, including the comments, suggests this isn't possible and might be an oversight in the standard.
I don't know how to solve the problem with using statement (it should look something like using A<C<T>>::template g;, but this code does not compile with my compiler). But you may call g<void> method in one of the following ways:
this->template g<void>()
A<C<T>>::template g<void>()
See the answers to this question for details about the dark side of using template keyword.

May a member function template specialization have a different access level than the main template?

An answer to a a question I had about deleting functions mentioned how member function templates can't be specialized at class scope. That led me to wonder if it's possible for a member function template specialization to have a different access level than the main template. In the code below, I'm trying to have a private specialization of a public member function template:
#include <iostream>
class Foo {
public:
template<typename T>
void func(T) { std::cout << "Public\n"; }
private:
template<>
void func<char>(char) { std::cout << "Private\n"; }
friend int main();
};
int main()
{
Foo f;
f.func(10);
f.func('a');
}
With the latest MSVC, this compiles, runs, and produces the expected output:
Public
Private
With g++ 4.8 and Clang 3.2, the code is rejected. Clang says this:
error: explicit specialization of 'func' in class scope
void func<char>(char) { std::cout << "Private\n"; }
^
Presumably g++ and Clang are using 14.7.3/2 of C++11 as the basis for their behavior, but I think there might be a little wiggle room, because 3.3.6/3 says that the global scope is a namespace, and the global namespace (indirectly) encloses the template specialization.
My question isn't about these parts of the Standard or about any of these compilers' behaviors, though, it's about whether it is possible for a member function template to have a specialization that has a different access level than the general template. For example, is it possible to have a public member function template and a private specialization of that template?
We can always do it manually.
Some random SFINAE machinery:
#include <iostream>
#include <utility>
#include <type_traits>
template<typename T> constexpr bool IsInt() { return std::is_same<T,int>::value; }
template<std::size_t>
struct SecretEnum {
enum class hidden {};
};
template<bool b, int i=1> using EnableIf = typename std::enable_if<b,typename SecretEnum<i>::hidden>::type;
class Foo {
public:
template<typename T, EnableIf< !IsInt<T>(), 1 >...>
void func(T) { std::cout << "Public\n"; }
private:
template<typename T, EnableIf< IsInt<T>(), 2 >...>
void func(T) { std::cout << "Private with int\n"; }
friend int main();
};
int main()
{
Foo f;
f.func(10);
f.func('a');
}
now this trick does not work with clang because of how I did the SFINAE and method distinguishing last I checked. But that can be replaced with other similar tricks (like pointer based default arguments in the second argument -- replace EnableIf< IsInt<T>(), 2 >... with EnableIf< IsInt<T>(), 2 >* = nullptr or somesuch for clang. I just find it less appealing.)
So what is going on above? I have two different overloads for func. Both are template functions with one argument that is a T, and a pack of some secret enum whose type is valid if and only if T matches the IsInt<T>() or !IsInt<T>() test respectively. The type of the packs differ in the two cases (one if them is SecretEnum<2>::hidden, the other is SecretEnum<1>::hidden), so their signatures are sufficiently different to satisfy most C++11 compilers (clang considers them to be identical last I checked, generating errors, I believe clang is wrong).
When you invoke func<blah>, it checks to see which (if any) of the two func are appropriate. As their conditions are exact opposites of each other, only one of them is ever the proper one.
In effect, we are doing manual specialization.
In C++1y, we may be able to template<IsInt T> and template<IsNotInt T> if the stars align properly and the concepts lite that gets into the technical report lets this work.

Is this a bug in GCC?

EDIT: This is not a bug, just me not knowing about dependent name lookups in templated base classes (which MSVC "helpfully" resolves without errors).
I wrote a functor implementation a while back, and a simple "Event" wrapper that uses it. It compiles fine under MSVC, but GCC gives an error about a member variable in the base class, subscribers, not being declared; changing subscribers to this->subscribers resolves the issue(!). It appears to happen only with the curiously recurring template pattern, and with partial template specialization.
Simplified source (sorry for the mind-bending template usage...):
#include <vector>
template<typename TEvent>
struct EventBase
{
protected:
std::vector<int> subscribers;
};
template<typename TArg1 = void, typename TArg2 = void>
struct Event : public EventBase<Event<TArg1, TArg2> >
{
void trigger(TArg1 arg1, TArg2 arg2) const
{
// Error on next line
auto it = subscribers.cbegin();
}
};
template<typename TArg1>
struct Event<TArg1, void> : public EventBase<Event<TArg1> >
{
void trigger(TArg1 arg1) const
{
// Using `this` fixes error(?!)
auto it = this->subscribers.cbegin();
}
};
template<>
struct Event<void, void> : public EventBase<Event<> >
{
void trigger() const
{
// No error here even without `this`, for some reason!
auto it = subscribers.cbegin();
}
};
int main()
{
return 0;
}
Am I invoking undefined behaviour somewhere? Is my syntax somehow wrong? Is this really a bug in GCC? Is it perhaps a known bug? Any insight would be appreciated!
More details: Compiled using g++ -std=c++11 main.cpp. I'm using GCC version 4.7.2. Exact error message:
main.cpp: In member function ‘void Event<TArg1, TArg2>::trigger(TArg1, TArg2) const’:
main.cpp:17:15: error: ‘subscribers’ was not declared in this scope
This is a bug in MSVC instead. Names from dependent base classes have to be "thisambiguated".
The reason is that unqualified lookup of dependent names proceeds in two phases. During the first phase, the base class is not yet known and the compiler cannot resolve the name. MSVC does not implement two-phase name lookup and delays the lookup until the second phase.
The full specialization
template<>
struct Event<void, void> : public EventBase<Event<> >
{
void trigger() const
{
// No error here even without `this`, for some reason!
auto it = subscribers.cbegin();
}
};
does not suffer from this problem, because both the class and its base are regular classes, not class templates, and there is no template dependency to begin with.
When porting C++ code from MSVC to gcc/Clang, dependent name lookup disambiguation and the template keyword disambiguation (i.e. calling member function template using ::template, ->template or .template syntax) are two of the subtleties that you have to deal with (empty base optimization is another one). For all the Standards compliance rhetoric, this will probably never be fixed for reasons of backwards compatibility.

Getting the address of template class object leads to full instantiation of template parameters

I got the errors compiling this code with g++ 4.6 and 4.8.
g++ 4.2 and 4.4 is OK. Is it a bug or some new language feature?
template <typename T>
struct A { typedef typename T::value_type type; };
template <typename U>
struct B
{
void bar () { }
void foo ()
{
// OK
this->bar ();
// OK
(*this).bar ();
// Error in g++ 4.6-4.8
// leads to full instantiating of template arg "U"
(&*this)->bar ();
}
};
int main ()
{
B< A<void> > b;
b.foo ();
return 0;
}
g++ inst.cc
inst.cc: In instantiation of ‘struct A<void>’:
inst.cc:20:5: required from ‘void B<U>::foo() [with U = A<void>]’
inst.cc:27:10: required from here
inst.cc:3:34: error: ‘void’ is not a class, struct, or union type
typedef typename T::value_type type;
^
Update 1: A cannot be instantiated, I know.
The question is: why the compiler tries to instantiate it at "(&*this)->bar ()" line, but not at "this->bar ()" or "(*this).bar ()" lines?
Update 2:
The suggested workaround with addressof (object) is not working for me, because actually I got the error when I tried to use std::bind (&B::bar, this). The real code is much more complex of course and the bind was not used standalone, but the problem was traced to the simple std::bind expression.
I did not want to rewrite or reinvent std::bind, so I had to use CRTP to make it work:
#include <tr1/functional>
template <typename T>
struct A { typedef typename T::value_type type; };
template <typename Derived, typename U>
struct B
{
Derived* derived (void) { return static_cast<Derived*>(this); }
void bar () { }
void foo ()
{
// error with recent compiler.
// std::tr1::bind (&B::bar, this) ();
// now ok
std::tr1::bind (&Derived::bar, derived ()) ();
}
};
struct C: B<C, A<void> >
{
};
int main ()
{
C c;
c.foo ();
return 0;
}
I find such errors and workarounds to be completely illogical though.
Analysis/explanation:
What you are seeing is shallow instantiation, not full (see below for proof).
ADL is the culprit here.
Hypothesis II I'm suspecting an ADL-related thing here (classes can have static free functions (friends) declared inline. Perhaps the compiler needs to instantiate the whole class template in order to make sure it has seen the operator overloads declared in it (in order to do overload resolution).
The standard backs me up here: §3.4.2 (p46 in n3337):
² [snip] The sets of namespaces and classes is determined entirely by
the types of the function arguments (and the namespace of any template
template argument). [snip] The sets of namespaces and classes are
determined in the following way:
[snip]
If T is a class type (including unions), its associated classes are: the
class itself; the class of which it is a member, if any; and its direct and
indirect base classes. Its associated namespaces are the namespaces of which
its associated classes are members. Furthermore, if T is a class template
specialization, its associated namespaces and classes also include: the
namespaces and classes associated with the types of the template
arguments provided for template type parameters (excluding template
template parameters); the namespaces of which any template template arguments
are members; and the classes of which any member templates used as template
template arguments are members.
The bolded phrase includes class A<void> as a lookup namespace for ADL.
Workaround:
In your situation std::addressof(b) can be used instead of &b and it will work.
Demonstration:
See http://liveworkspace.org/code/4f85a06598eebe1d8060112be36f4a29
Note: the (unqualified-id) trick is defined in §3.4.2 of the standard)
#include <vector>
#include <iostream>
struct Base {};
template <typename U> struct B : Base { };
template <typename T> struct A {
typedef typename T::value_type type;
friend void freefunction(B<A>&) { std::cout << "ADL was here!\n"; }
};
void freefunction(Base& /*acceptAll*/) {}
int main ()
{
B< A<std::vector<int> > > a;
B< A<void> > b;
// surrounding with parens prevents ADL:
(freefunction)(a);
(freefunction)(b); // selects ::freefunction(Base&)
freefunction(a); // ADL selects friend inline freefunction(B< A<std::vector<int> > >&)
//freefunction(b); // ADL fails: template arg cannot be (shallow) instantiated
}
Prints
ADL was here!
Also, you can verify that the template argument (A<void>) gets shallow instantiated only. Moving the ill-formed typedef into a member function removes the problem:
template <typename T> struct A {
void uninstantiated() {
typedef typename T::value_type type;
}
friend void freefunction(B<A>&) { std::cout << "ADL was here!\n"; }
};
Outputs (http://liveworkspace.org/code/a15c933293281d0926e8b1ff39180079)
ADL was here!
ADL was here!
History:
I noticed operator& was the problem, but std::addressof() was ok!
I noticed use of any (overloaded) operators seems to trigger this behaviour
This lead me to my 'Hypothesis II' (see above)