What's wrong with this code? gcc 4.6.1 is complaining "‘foo’ was not declared in this scope" in baz(). If I transform the code so that one of the templates is just a regular class, the problem goes away.
struct Foo {
char foo;
};
template<int N>
struct Bar : public Foo
{
Bar() { foo; }
};
template<int N>
struct Baz : public Bar<N>
{
void baz() { foo; }
};
int main() {
Baz<10> f;
return 0;
}
What is wrong, according to the specifications, I don't know, but you may make your code to compile by using:
void baz() { Bar<N>::foo; }
foo is a dependent name; that is, it depends on the template parameter, so until the template is instantiated the compiler doesn't know what it is. You have to make it clear that it is a class member, either Bar<N>::foo or this->foo.
(You probably also want to do something with it; simply using it as the ignored value of an expression doesn't do anything at all).
Related
Hello template wizards,
I have been concocting a utility template which has one problem left to be solved, but cannot seem to figure it out. The code in this post is a simplification of the code in question, which exhibits the same issue.
Suppose you have a template specialisation as shown below.
enum class Pets { Dog, Cat, Bird };
template <Pets variant>
class Animal;
template <>
class Animal<Pets::Cat> {
void Sound();
};
template <>
class Animal<Pets::Dog> {
void Sound();
};
template <>
class Animal<Pets::Bird> {
void Sound();
};
void Animal<Pets::Cat>::Sound() { printf("Meow!\n"); }
void Animal<Pets::Dog>::Sound() { printf("Woof!\n"); }
void Animal<Pets::Bird>::Sound() { printf("Peep!\n"); }
And then I ruin everything by saying that I might not declare the specialisation of Animal<Pets::Bird>. The latter definition of ::Sound() will fail to compile, as the type doesn't exist. Now, this seems to beg for a SFINAE solution, to me, as we have an unwanted method implementation of a type that we don't want to exist.
I'd like the compiler to simply ignore that last method definition instead of failing compilation, without changing the method signature — that is, I don't want to make the method itself a template.
Do you have any suggestions on how to make this work?
You can’t do this: SFINAE is about overload resolution, and while it also supports the very similar case of selecting a partial specialization, it’s not a general conditional compilation technique. You can use the preprocessor, of course, and you can do tricks like declaring the unwanted function private so that it “doesn’t exist”, but you can’t define a function that just is never mentioned.
I did manage to conjure up a solution, which quite neatly just declares a catch-all, for those types are to be discarded — not quite what I asked for, but closer toward the goal.
This, at least, takes care of the definitions of methods that would otherwise fail compilation.
enum class Pets { Dog, Cat, Bird };
static constexpr Pets kChosenPet = Pets::Cat;
struct AbstractAnimal {
virtual void Sound() = 0;
};
template <Pets variant = kChosenPet, bool B = (variant == kChosenPet)>
struct Animal : public AbstractAnimal {
void Sound();
};
template <Pets variant>
struct Animal<variant, true> : public AbstractAnimal {
void Sound();
};
template <>
void Animal<Pets::Cat>::Sound() {
printf("Meow!\n");
}
template <>
void Animal<Pets::Dog>::Sound() {
printf("Woof!\n");
}
template <>
void Animal<Pets::Bird>::Sound() {
printf("Peep!\n");
}
May be I don't understand something in your question. But what's wrong with just moving declaration of Sound() to Animal?
#include <stdio.h>
#include <type_traits>
enum class Pets { Dog, Cat, Bird };
template <Pets variant>
class Animal {
void Sound();
};
template<>
void Animal<Pets::Cat>::Sound() { printf("Meow!\n"); }
template<>
void Animal<Pets::Dog>::Sound() { printf("Woof!\n"); }
template<>
void Animal<Pets::Bird>::Sound() { printf("Peep!\n"); }
"SFINAE" means "Substitution Failure Is Not An Error". That starts with "Subsitution", an early part of the template instantiation process. And SFINAE is only Not An Error when there are alternatives for the failed template, e.g. other function overloads.
Now in void Animal<Pets::Bird>::Sound(), there is no Substitution, so SFINAE can't apply. We can't introduce it either - the normal way is via std::enable_if, which can turn a non-template declaration into a template declaration that might or might not be instantiated. But that doesn't work - this specialization cannot be a template declaration.
This case can be simplified:
#ifdef FOO
class Foo { int bar; }
#endif
int Foo::bar() { return 1; } // Also not fixable by SFINAE, for the same reason.
This question already has an answer here:
Why can I call base template class method from derived class
(1 answer)
Closed 2 years ago.
I have a template struct which inherits another template struct. It fails compilation in different compilers (in VS2017 and clang on linux). A simple change in the code fixes it.
The code is:
template<typename T>
struct base {
int GetValue2() { return 0; }
};
template<typename T>
struct derived : public base<T>
{
int GetValue() { return GetValue2(); }
};
int main() {
derived<int> a;
return 1;
}
If I change the line
int GetValue() { return GetValue2(); }
to:
int GetValue() { return this->GetValue2(); }
everything compiles just fine.
Does anyone have an idea what's going on?
There is a two-stage name lookup here.
In GetValue(), GetValue2 is not used in a dependent context, so the compiler will look for a name declared at the enclosing namespace scope (which is the global scope here).
It will not look into the base class, since that is dependent and you may declare specializations of Base even after declaring Derived, so the compiler can't really know what i would refer to. If there is no global variable i, then you will get an error message.
In order to make it clear that you want the member of the base class, you need to defer lookup until instantiation time, at which the base class is known. For this, you need to access i in a dependent context, by either using this->i (remember that this is of type Derived*, so is obviously dependent), or using Base::i. Alternatively, Base::i might be brought into scope by a using-declaration.
template<typename T>
struct base {
int GetValue2() { return 0; }
};
template<typename T>
struct derived : public base<T>
{
int GetValue_using() {
using base<T>::GetValue2; // won't compile with gcc, place it outside the function (ok with clang and msvc)
return GetValue2();
}
int GetValue_this() { return this->GetValue2(); }
int GetValue_base() { return base<T>::GetValue2(); }
};
int main() {
derived<int> a;
return 1;
}
Lets say I have the follow code
template<class MemberFunc>
class Foo {
MyClass object_;
void call() {
auto ptr = MemberFunc{};
(object_.*ptr)();
}
};
int main() {
Foo<decltype(&MyClass::doThings)> foo;
foo.call();
}
This code does crash for me because ptr is 0. Why does the member function constructor returns 0?
My workaround is the following but it involves code duplication. Is there no other way to just construct/instantiate the member function from the type? C++14 welcome.
template<class MemberFunc, MemberFunc f>
class Foo {
MyClass object_;
void call() {
(object_.*f)();
}
};
int main() {
Foo<decltype(&MyClass::doThings), &MyClass::doThings> foo;
foo.call();
}
Why does the member function constructor returns 0?
Because it's a pointer (-to-member-function), and all scalar types value-initialize to 0 (C++14 [dcl.init]/8.4).
Is there no other way to just construct/instantiate the member function from the type?
You can have multiple member functions with the same signature; how would it know which member function you want to refer to?
The code you have is fine for C++14. In C++17, it can be shortened to the following:
template<auto f>
class Foo {
MyClass object_;
void call() {
(object_.*f)();
}
};
int main() {
Foo<&MyClass::doThings> foo;
foo.call();
}
You can't instantiate a member function from its type. For example, consider the following class:
struct foo
{
void bar(int){}
void baz(int){}
};
Suppose you have a type void (foo::*)(int). Which function would you like to get from it?
As of C++1z, you'll be able to use auto to deduce non-type, non-template template parameters:
template<auto f>
class Foo {
MyClass object_;
void call() {
(object_.*f)();
}
};
int main() {
Foo<&MyClass::doThings> foo;
foo.call();
}
demo
The only workaround for C++11/14 I can think of is using a macro:
#define type_value_pair(x) decltype(x), x
template<class MemberFunc, MemberFunc f>
class Foo {
MyClass object_;
void call() {
(object_.*f)();
}
};
int main() {
Foo<type_value_pair(&MyClass::doThings)> foo;
foo.call();
}
demo
But I'd advise against using this, for readability reasons.
decltype returns the type of its argument. Using the following example:
class MyClass {
public:
int foo();
int bar();
};
Both
decltype(&MyClass::foo);
and
decltype(&MyClass::bar);
is the same type: int (MyClass::*)().
When you default-initialize this type, the default initialization results in a nullptr. Hence the crash.
When you value-initialize a pointer to member-function, you will receive a nullptr, of course.
By the way, you can have multiple member function with the same type as you can see in Sam's answer.
I don't know why do you need to put the MemberFunc to template parameter list of Foo.
However, if you want to make a function to call it, this maybe a better approach in C++ before C++1z (use auto in C++1z is better match for this question):
class Foo {
MyClass object_;
public:
template<class MemberFunc>
void call(MemberFunc ptr) {
(object_.*ptr)();
}
};
int main() {
Foo foo;
foo.call(&MyClass::doThings);
}
I found detect class 's member use global template function is not work:
void printinfo(std::true_type)
{
cout<<"true_type!";
}
void printinfo(std::false_type)
{
cout<<"false_type!";
}
class TestAA
{
public:
void foo();
};
class TestBB;
template<typename T,typename =decltype(&T::foo)>
std::true_type havefoo(T*){return{};}
std::false_type havefoo(...){return{};}
int main()
{
printinfo(havefoo((TestAA*)nullptr));
printinfo(havefoo((TestBB*)nullptr));
}
class TestBB
{
public:
void foo();
};
it fail detect TestBB's foo,is normal? or a complier bug? gcc 4.8.1
The compiler hasn't seen the definition of TestBB at the point of the call to printinfo, only the forward declaration. At that point it doesn't know about any members of TestBB.
template<typename T> struct A {
auto func() -> decltype(T::func()) {
return T::func();
}
};
class B : public A<B> {
void func() {
}
};
Seems pretty simple to me. But MSVC fails to compile.
visual studio 2010\projects\temp\temp\main.cpp(4): error C2039: 'func' : is not a member of 'B'
visual studio 2010\projects\temp\temp\main.cpp(8) : see declaration of 'B'
visual studio 2010\projects\temp\temp\main.cpp(8) : see reference to class template instantiation 'A<T>' being compiled
with
[
T=B
]
visual studio 2010\projects\temp\temp\main.cpp(4): error C3861: 'func': identifier not found
Even though the compiler will happily accept calling the function. The below sample compiles fine.
template<typename T> struct A {
void func() {
return T::func();
}
};
class B : public A<B> {
void func() {
}
};
I've got the same issue trying to use any types from the template argument.
template<typename T> struct A {
typedef typename T::something something;
};
class B : public A<B> {
typedef char something;
};
visual studio 2010\projects\temp\temp\main.cpp(4): error C2039: 'something' : is not a member of 'B'
Whereas class B clearly defines a type called "something". The compiler is perfectly happy to call functions on an object of type T, T& or T*, but I can't seem to access any types from T.
You are trying to use T::func before it was declared. That's why the compiler shouts at you. Notice that when you derive from a class, the class is generated if it comes from a class template. And the implicit generation of the class (which is called implicit instantiation) necessiates the generation of declarations for all its members (so the compiler knows the sizeof value of the class, and can perform lookup into it).
So it also instantiates the declaration auto func() -> decltype(T::func()) and surely fails here.
There seem to be several issues with your code, one of which looks like a VS10 bug.
You're calling T::func() from A without casting A to T, this is needed as part of CRTP since A doesn't derive from T. -- FixL return static_cast<T*>(this)->func();
What you're passing to decltype looks like a static function invocation while func is in fact an instance function. Since decltype doesn't actually run the function you should do something like this decltype(static_cast<T*>(nullptr)->func())
func is private in B and can't be called from A -- Fix: change A to be a struct
This looks like a bug in VS10, even after all these fixes I get an error that you're trying to use an undefined class B in the decltype.
As a workaround can you refactor func out into a base class? (now we need two template parameters, one for casting to and one for decltype thus creating a new idiom CRTPEX)
struct Base {
void func() { }
};
template<typename T, typename U> struct A {
auto func() -> decltype(static_cast<T*>(nullptr)->func()) {
return static_cast<U*>(this)->func();
}
};
struct B : public A<Base, B>, public Base {
};
I see that g++ also chokes on this decltype can anyone confirm that this is a defect? If so I will open a bug for Microsoft. It is my understanding that the following code is valid but neither g++ nor VC10 compile it.
template<typename T> struct A {
auto func() -> decltype(static_cast<T*>(nullptr)->func()) {
return static_cast<T*>(this)->func();
}
};
struct B : public A<B> {
void func() {}
};
First, I think that the close-to-proper code is:
template<typename T> struct A {
auto func()
-> decltype(static_cast<T*>(this)->func())
{
return static_cast<T*>(this)->func();
}
};
class B : public A<B> {
void func(){
}
};
As Motti pointed out. However that still fails, and I think for the reason that the return type of the base has to be known when B is declated to inherit from A<B>, but since B is not defined yet, it becomes a chicken and egg problem.
However, it may be finally be possible in C++1y by using simply auto (without decltype), I tried with gcc-4.8.2
template<typename T> struct A {
auto func()
//c++1y// -> decltype(static_cast<T*>(this)->func())
{
return static_cast<T*>(this)->func();
}
};
class B : public A<B> {
void func(){
}
};
This compiles (c++ -std=c++1y) and runs:
int main(){
B b; b.func();
}
Two disclaimers: I don't know why this works. I don't know how standard it is.