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.
Related
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.
I've created a concept checking class based on this question whose purpose is to make sure a given class has a static member function called baseUnitConversionFactor. The class compiles and works fine with msvc2013, but it wont compile on gcc 4.9.2 (using -std=c++14) with the error:
error: ‘{anonymous}::UnitsTest_conceptChecker_Test::TestBody()::validUnit::baseUnitConversionFactor’
is not a valid template argument for type ‘double (*)()’ because
‘static double {anonymous}::UnitsTest_conceptChecker_Test::TestBody()::validUnit::baseUnitConversionFactor()’
has no linkage
static std::true_type test(tester<&U::baseUnitConversionFactor>*);
I don't really know what that means, and am much more familiar with writing templates in visual studios (obviously) much more permisive enviornment. Can anyone help figure out what I need to do to fix this?
Concept Checker Class
template <typename T>
struct has_baseUnitConversionFactor
{
template<double(*)()> struct tester;
template<typename U>
static std::true_type test(tester<&U::baseUnitConversionFactor>*);
template<typename U>
static std::false_type test(...);
static const bool value = decltype(test<T>(0))::value;
};
Test which I think causes the error
TEST_F(UnitsTest, conceptChecker)
{
struct validUnit
{
static inline double baseUnitConversionFactor() { return 0.0; }
typedef void unit_category;
typedef void base_unit_type;
};
EXPECT_TRUE(has_baseUnitConversionFactor<validUnit>::value);
}
In C++11 and C++14, pointer/reference template arguments must refer to entities with linkage (in C++03, they were limited to entities with external linkage). A local class has no linkage, and neither do its member functions.
This restriction has been removed in C++17 by N4268, and GCC trunk claims to have implemented that paper, but apparently not the linkage part.
Sidestepping this issue requires not using &U::baseUnitConversionFactor as a template non-type argument. Happily, a much simpler way to test that the expression T::baseUnitConversionFactor() is valid and returns exactly double is:
template <typename T, class=double>
struct has_baseUnitConversionFactor : std::false_type { };
template <typename T>
struct has_baseUnitConversionFactor<T, decltype(T::baseUnitConversionFactor())>
: std::true_type { };
This does depend on expression SFINAE (but then, so does the original), so I'm not sure if it will work on MSVC 2013.
For a more general check, you may want to look at std::experimental::is_detected_convertible. That cppreference page has a reference implementation.
Annoyingly, the problem seems to be caused by the way gtest uses anonymous namespaces. Moving the validUnit declaration into the test fixture (called UnitsTest) and changing the EXPECT statement to use the fixture namespace solved the issue.
Updated Fixture
class UnitsTest : public ::testing::Test {
protected:
UnitsTest()
{
}
virtual ~UnitsTest()
{
}
virtual void SetUp()
{
}
virtual void TearDown()
{
}
struct validUnit
{
static inline double baseUnitConversionFactor() { return 0.0; }
typedef void unit_category;
typedef void base_unit_type;
};
};
Updated Test
TEST_F(UnitsTest, conceptChecker)
{
EXPECT_TRUE(has_baseUnitConversionFactor<UnitsTest::validUnit>::value);
}
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.
I am writing a heavily templated piece of code in C++. It worked perfectly in VS 2005 but when I try to compile it in g++ I get some really strange errors.
The essential piece of code (simplified to a minimum, doesn't compile either) is as follows:
template <class Actual>
class Generic
{
public:
typedef Actual ThisType;
};
template <class Actual>
class Intermediate : public Generic<Actual>
{
};
template <class Q>
class Derived : public Intermediate<Derived<Q> >
{
public:
void FooBar()
{
ThisType q;
}
};
The error is:
"'ThisType' was not declared in this scope"
in the line where 'q' is being declared.
Curiously, everything works fine when Derived is not a template but a plain class. Why would compiler look into template function implementation before it is even instantiated? I know that VC++ checks far too little when compiling templates (unused templates can even contain syntactically incorrect code) - but isn't g++ checking too much here? I tried adding a typename keyword with little hope and it fails too. Is there any way to get ThisType to work as expected? I dread the thought of adding it manually to every single derived class - it's cumbersome, redundant, inelegant and error-inducing.
Best regards,
MZ
Unqualified names are not looked up in dependent base classes (your base class depends on template parameter Q). Qualify that name, and it will work.
typename Derived::ThisType q;
Trust in Comeau online compiler!
Comeau C/C++ 4.3.10.1 (Oct 6 2008 11:28:09) for ONLINE_EVALUATION_BETA2
Copyright 1988-2008 Comeau Computing. All rights reserved.
MODE:strict errors C++ C++0x_extensions
"ComeauTest.c", line 19: error: identifier "ThisType" is undefined
ThisType q;
^
"ComeauTest.c", line 19: error: expected a ";" (perhaps on the previous statement)
ThisType q;
^
2 errors detected in the compilation of "ComeauTest.c".
Dependent type names from inherited classes are not taken into account, you might try to explicitly request ThisType:
typename Intermediate<Derived<Q> >::ThisType q;
The code is indeed ill-formed. When base class depends on template parameter it is not considered by name lookup when looking for unqualified names.
In your case unqualified name ThisType will not be looked up in base class Intermediate<Derived<Q> > because your base class depends on template parameter Q.
You are missing a typename
template <class Actual> class Generic { public:
typedef Actual ThisType; };
template <class Actual> class Intermediate : public Generic<Actual> { };
template <class Q> class Derived : public Intermediate<Derived<Q> > { public:
void FooBar()
{
typename Derived::ThisType q;
return *this;
} };
int main(){}
I'm working on some code that compiles and links (and even has released commercial products) on Windows using MSVC. It doesn't compile with GCC though, I get the following errors:
.../CBaseValue.h: In member function 'bool CBaseValue::InstanceOf()':
.../CBaseValue.h:90:18: error: invalid use of incomplete type 'struct CValueType'
.../CBaseValue.h:11:7: error: forward declaration of 'struct CValueType'
CBaseValue.h
class CValueType;
class CBaseValue {
public:
...
template <typename _Type>
bool InstanceOf() {
CValueType* pType = GetType();
if(pType == NULL) {
return false;
}
else {
return pType->IsDerivedFrom<_Type>();
}
}
...
}
CValueType.h
class CValueType : public CBaseValue {
public:
...
template <typename _Type>
bool IsDerivedFrom() {
return IsDerivedFrom(_Type::TYPEDATA);
}
...
}
I understand why this is a problem. The base class (CBaseValue) has a templated function that uses a derived class (in this case CValueType).
It looks like MSVC isn't exactly obeying the C++ spec here and I've just been bitten by it. But the MSVC behavior of using the forward declaration until code calling the templated function is actually compiled is also more desirable right now. Does anybody know of a work-around where I can get this code working with GCC without having to rewrite a lot of base code?
From my own research it looks like passing '-fno-implicit-templates' to g++ would help but then I'd need to explicitly define the called template types. There are a lot of them so if I can avoid that I'd prefer it. If the general consensus is that this is my best option... so be it!
And in case anybody is wondering, I'm porting the code over to the Mac which is why we're now using GCC.
This is ill-formed by the Standard, but no diagnostic is required. MSVC is fine not diagnosing this particular case (even when instantiation happens!).
More specifically, the (C++03) Standard rules at 14.6/7
If a type used in a non-dependent name is incomplete at the point at which a template is defined but is complete at the point at which an instantiation is done, and if the completeness of that type affects whether or not the program is well-formed or affects the semantics of the program, the program is ill-formed; no diagnostic is required.
So the solution is to just make the type dependent, but arrange it that during instantiation, that type is designated. For example, you can do that by rewriting your template like this
template<typename T, typename> // just ignore second param!
struct make_dependent { typedef T type; };
template <typename Type> // eww, don't use "_Type" in user code
bool InstanceOf() {
typename make_dependent<CValueType, Type>::type* pType = GetType();
// ...
return pType->template IsDerivedFrom<Type>();
// ...
}
It seems that the CBaseValue::InstanceOf() function is useless to anyone not including CValueType.h.
So wait to provide the definition until all needed types are available. (EDIT: This is exactly what is suggested by Charles Bailey's comment that he posted while I was typing -- I guess we think alike.)
CBaseValue.h
class CValueType;
class CBaseValue {
public:
...
template <typename _Type>
bool InstanceOf();
...
}
CValueType.h
class CValueType : public CBaseValue {
public:
...
template <typename T>
bool IsDerivedFrom() {
return IsDerivedFrom(T::TYPEDATA);
}
...
}
template <typename T>
inline bool CBaseValue::InstanceOf() {
CValueType* pType = GetType();
if(pType == NULL) {
return false;
}
else {
return pType->IsDerivedFrom<T>();
}
}
They seem very tightly coupled though, so maybe having just one header file for both classes, or one public header file that includes the individual headers in the correct order, would be better.