SFINAE'ing out definitions of classes that don't exist - c++

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.

Related

Same non-template member function definition for multiple types of template class specilization

Is it possible that some types of specialized class share one non-template member function definition of a declaration, some types of specialized class share another non-template member function definition with the same declaration in class as above, and the function definitions is in cpp not hpp?
for example: I have a template class A with non-template member function p
template <typename T>
class A {
void p() {
print("food.\n");
}
};
And I have 4 types: banana, apple, fish, steak to specialize the class A for usage in main.cpp:
if A is specialized as A<banana>, A<apple>, p print "fruit",
if A is specialized as A<fish>, A<steak>, p print "meat".
I would not write 2 times of version: print "fruit" 2 times of version: print "meat" 2 times. Meanwhile, since which type of specialized class print what text has been concrete, is it possible that the 2 versions of p definition could be write in cpp files to reduce cost of compilation?
Maybe use if constexpr to check types and print accordingly.
#include <iostream>
struct Fish {};
struct Steak {};
struct Banana {};
struct Apple {};
template <typename T>
class A {
public:
void p() {
if constexpr(std::is_same_v<T, Apple> || std::is_same_v<T, Banana>)
std::cout << "Fruit\n";
else if constexpr(std::is_same_v<T, Fish> || std::is_same_v<T, Steak>)
std::cout << "Meat\n";
}
};
int main()
{
A<Fish> fish;
A<Apple> apple;
fish.p();
apple.p();
}
Inheritance might help you out in this case:
class Fruit
{
protected:
void p() { /* ... */ }
};
class Meat
{
protected:
void p() { /* ... */ }
};
// general case left unimplemented not to allow arbitrary instantiations
template <typename T>
class A;
// (alternatively you might provide a default implementation handling the unspecific case)
template <>
class A<Apple> : Fruit
{
public: using Fruit::p;
};
template <>
class A<Fish> : Meat
{
public: using Fruit::p;
};
If it is meaningful to provide a public type hierarchy is up to you to decide, you might then add a generic root class Food with a pure virtual p (then public, of course) while you'd let Fruit and Meat have overrideing p. This would e.g. allow to add the different types of food to a container, but you need to use (smart?) pointers for to avoid object slicing.
Public inheritance with public p in the base classes could be applied for convenience only, too, for not having to specify the using clause – though convenience for the implementer of types usually leads to less clean code in the end...

Nested Type of Template not depending on Template Arguments

I've been struggeling with the following problem:
// this is in a header file
template <typename T>
struct Foo {
T x, y;
// ... other stuff
struct Bar {
int a, b;
// ... other stuff
void f() const;
};
Bar h() const
{ return { reinterpret_cast<int>(this->x), reinterpret_cast<int>(this->y) }; }
};
It's clear that Foo::h() needs to be implemented in the header file since it depends on the template argument.
But this is not the case for Foo::Bar::f().
I would like to implement this in a separate .cpp-file, since it only needs to compile once and so on.
Just as a note: I would like to keep this as a nested type for namespacing reasons.
Is there a nice way to do this ?
I dont't see why this shouldn't work, since Foo::Bar does not depend on the template argument at all.
Thank you very much !
Edit: fixed typo
I dont't see why this shouldn't work, since Foo::Bar does not depend on the template argument at all
This is not correct conclusion - the nested class has access to all names (private, protected, etc) to which the enclosing class has access, so depending on how the enclosing class is instantiated, the nested class has different surrounding context, thus Foo<int>::Bar and Foo<char>::Bar are not the same classes (to be precise - the nested class is part of the enclosing class definition, so without Foo<int>/Foo<char>, Bar doesn't exist, but since these are different classes, Bar under those classes are also different)
not sure what you mean by "namespacing reasons", but if you just want to access it like Foo<T>::Bar, you can use alias.
struct ChocolateBar {
int a, b;
// ... other stuff
void f() const;
};
template <typename T>
struct Foo {
T x, y;
// ...
using Bar = ::ChocolateBar;
Bar h() const { return { reinterpret_cast<int>(this->x), reinterpret_cast<int>(this->y) }; }
};

Why are function template specializations not allowed inside a class?

After having found answers to many of my questions on stackoverflow, I have now come up against a question of which I can't find the answer and I hope that someone is willing to help me!
My problem is that I want to do an explicit templatization of a function inside a class in C++. My compiler (g++) and a look in the C++ standard (§14.7.3) tells me that this specialization has to be done in the namespace in which the class is declared. I understand that this implies that I cannot put the specialization inside the class, but I don't see the point of this restriction! Does anyone know if there is a good reason for not letting the specializations be made inside the class?
I know that there are workarounds, e.g. to put the function inside a struct, but I want to understand why the language has this design. If there is a good reason for not allowing specialized functions inside the class, I guess I should know it before trying to work around it.
Thanks in advance!
To make my question a little bit more precise: Here is some code from a test example which illustrates what I want to do:
#include <cstdio>
namespace MalinTester {
template <size_t DIMENSIONALITY>
class SpecializationTest {
public:
SpecializationTest() {
privateVariable = 5;
};
virtual ~SpecializationTest() {};
void execute() {
execute<DIMENSIONALITY>();
};
private:
int privateVariable;
template <size_t currentDim>
static void execute() {
printf("This is the general case. Current dim is %d. The private variable is %d.\n", currentDim, privateVariable);
execute<currentDim-1>();
}
template <>
static void execute<0>() {
printf("This is the base case. Current dim is 0.\n");
}
};
This is not possible; g++ says:
SpecializationTest_fcn.h:27: error: explicit specialization in non-namespace scope ‘class MalinTester::SpecializationTest<DIMENSIONALITY>’
SpecializationTest_fcn.h:28: error: template-id ‘execute<0>’ in declaration of primary template
If I put the function execute outside the class, in the name space MalinTester, it will look like this:
#include <cstdio>
namespace MalinTester {
template <size_t DIMENSIONALITY> class SpecializationTest {};
template <size_t currentDim>
void execute() {
printf("This is the general case. Current dim is %d. The private variable is %d.\n", currentDim, privateVariable);
execute<currentDim-1>();
}
template <>
void execute<0>() {
printf("This is the base case. Current dim is 0.\n");
}
template <size_t DIMENSIONALITY>
class SpecializationTest {
public:
SpecializationTest() {};
virtual ~SpecializationTest() {};
void execute() {
MalinTester::execute<DIMENSIONALITY>();
};
private:
int privateVariable = 5;
};
};
};
and I cannot use privatevariable in the templatized versions of execute, as it is private in the class. I really want it private, as I want to have my data encapsulated as far as possible.
Of course I can send privateVariable as an argument to the function, but I think it would be more beautiful to avoid this, and what I really wonder is if there is a good reason for the C++ standard not to allow explicit specialization as in the first code example above.
#Arne Mertz: This is the workaround I have tried, but it doesn't allow using privateVariable either. And most of all, I wonder if it is a good idea to do like this. As I'm not allowed to make specializations of member functions, maybe I shouldn't do specializations of functions encapsulated in structs inside the class either.
#include <cstdio>
namespace MalinTester {
template <size_t DIMENSIONALITY>
class SpecializationTest {
public:
SpecializationTest() {
privateVariable = 5;
};
virtual ~SpecializationTest() {};
void execute() {
Loop<DIMENSIONALITY, 0>::execute();
};
private:
int privateVariable;
template <size_t currentDim, size_t DUMMY>
struct Loop {
static void execute() {
printf("This is the general case. Current dim is %d.\n", currentDim);
Loop<currentDim-1, 0>::execute();
}
};
template <size_t DUMMY>
struct Loop<0, DUMMY> {
static void execute() {
printf("This is the base case. Current dim is 0.\n");
}
};
};
};
Base specialization:
In .h:
template <class T>
class UISelectorSlider : public UISelectorFromRange<T> {
public:
UISelectorSlider();
virtual ~UISelectorSlider();
private:
float width;
float getPositionFromValue(T value);
};
In .cpp under same namespace:
template <>
float UISelectorSlider<MVHue>::getPositionFromValue(MVHue value)
{
return width * (float)value / 360.0;
}
If you want specialized function within specialized class:
Inside class add (.h) (private function):
private:
template <int I>
void foo();
Specialization inside .cpp:
template <>
template <>
void UISelectorSlider<MVHue>::foo<3>()
{
// you can access private fields here
}
UPDATE:
But you cant write something like this:
template <class T>
template <>
void UISelectorSlider<T>::foo<3>()
{
// you can access private fields here
}
You will get: error: enclosing class templates are not explicitly specialized.
It does not matter is this definition inside class or in namespace. The point is that this is not exact partial specialization - this function does not have defined context class (which members you want to call). In other words - when you specialize member you actually try specialize the whole containing class, but not the member itself. And compiler cant do that because class is not yet defined completely. So this is restriction by template design. And if it actually worked - templates would be full equivalent to simple macros.
(And you probably can will solve your task with some macro magic.)

checking class in c++ templates without class instance

I need to write template which generates some code depending on whether template parameter is instance of of some class. The template can be generated for all classes but only in case the class is subclass of other class the code should be executed.
The problem is that function that should be implemented does not receive any instance of the class, so the only thing known is class name. So it is impossible to achieve this with dynamic_cast as it demands instance of the object
template<T>
class A
{
void somefunction(void)
{
if (T instanceof Foo) then ...
else ...
}
}
adding some explanation
class X: public Foo {};
class Y {};
class A<X> {} // special logic is generated
class A<Y> {} // special logic is NOT generated
You can use template specialization or boost::is_base_of from the boost traits library
Or of course write your own traits, but shouldn't, for you have not mastered templates yet.
Using specialization, you could
template<T>
class A
{
void somefunction() {
// generic version
}
};
template<>
class A <Foo>
{
void somefunction() {
// foo version
}
};
As always, let me recommend Vandevoorde/Josuttis "C++ Templates: The Complete Guide".
If you fear code bloat because only one memberfunction out of many needs to be specialized, you can still outsource that function:
template <typename T> struct somefunction_helper {
static void thatfunction () {
// generic form
}
};
template <> struct somefunction_helper<Foo> {
static void thatfunction () {
// Foo form
}
};
template<T>
class A
{
void somefunction() {
somefunction_helper<T>::thatfunction();
}
};
This is what template specializations are for. They're more difficult to write, but that's what you do with them. For example:
template<T> class A
{
void somefunction(void) {
...//default for any object type.
}
};
template<> class A<Foo>
{
void somefunction(void) {
...//specific to the type Foo.
}
};
Yes, it requires an extra bit of work. There are some template metaprogramming ways to do this the way you want, but someone else will have to explain those.
Either specialize A or delegate the work of the someFunction() member function template to some free function template which you can (fully) specializes on T.
Since specialization won't work since the template parameter will only ever be derived from Foo, use what another answer said: is_base_of, either from Boost or from the standard library if it already supports parts of C++0x:
#include <type_traits> // C++0x
class Foo{};
template<class T>
class A{
void specialOnFoo(){
// dispatch the call
specialOnFoo(std::is_base_of<T, Foo>::type());
}
void specialOnFoo(std::true_type){
// handle Foo case
}
void specialOnFoo(std::false_type){
// non-Foo case
}
};
Edit #2 - see working example. Please note that this the run-time equivalent of template specialization (which happens at compile-time) and requires RTTI enabled.
#include <iostream>
#include <typeinfo>
using namespace std;
class Foo {};
class X: public Foo {};
class Y {};
template<typename T> class A {
public:
void somefunction()
{
if (typeid(T) == typeid(X)) {
cout << "X specific logic happening" << endl;
}
else {
cout << "Default behavior" << endl;
}
}
};
int main() {
A<X> ax;
A<Y> ay;
ax.somefunction(); // prints "X specific logic happening"
ay.somefunction(); // prints "Default behavior"
}
typeid can be used with templates to extract the type of the template parameter -- as described below:
// expre_typeid_Operator_3.cpp
// compile with: /c
#include <typeinfo>
template < typename T >
T max( T arg1, T arg2 ) {
cout << typeid( T ).name() << "s compared." << endl;
return ( arg1 > arg2 ? arg1 : arg2 );
}
Taken from: http://msdn.microsoft.com/en-us/library/fyf39xec(v=vs.80).aspx
Note that the value of name() is implementation defined.

typename when defining map data that is a function pointer with a sprinkling of templates

This is a strange question because I already know the 'coding' answer. I just want to get a better understanding of why it is so. There are guru's here who have a knack of explaining these things better than the C++ standard :)
Below we have a means to define an abstract factory template that allocates objects based on a string as a key (it is a contrived example):-
#include <iostream>
#include <map>
#include <string>
using namespace std;
template <typename T, typename TProduct>
TProduct *MyFactoryConstructHelper(const T *t)
{
if (!t) return new T;
return new T(*static_cast<const T*>(t));
}
template <typename TProduct>
class AbstractFactory
{
public:
typedef TProduct *(*MyFactoryConstructor)(const void *);
typedef map<string, MyFactoryConstructor> MyFactoryConstructorMap;
static TProduct *Create(const string &iName)
{
MyFactoryConstructor ctr = mTypes[iName];
TProduct *result = NULL;
if(ctr) result = ctr(NULL);
return result;
}
template <typename T>
static bool Register(const string &iName) {
typedef TProduct*(*ConstructPtr)(const T*);
ConstructPtr cPtr = MyFactoryConstructHelper<T, TProduct>;
string name = iName;
mTypes.insert(pair<string,MyFactoryConstructor>(name, reinterpret_cast<MyFactoryConstructor>(cPtr)));
return(true);
}
protected:
AbstractFactory() {}
static MyFactoryConstructorMap mTypes;
};
template <typename TProduct>
map<string, /*typename*/ AbstractFactory<TProduct>::MyFactoryConstructor> AbstractFactory<TProduct>::mTypes;
Here is an example of how we use it: -
class MyProduct
{
public:
virtual ~MyProduct() {}
virtual void Iam() = 0;
};
class MyProductFactory : public AbstractFactory<MyProduct>
{
public:
};
class ProductA : public MyProduct
{
public:
void Iam() { cout << "ProductA" << endl; }
};
class ProductB : public MyProduct
{
public:
void Iam() { cout << "ProductB" << endl; }
};
int _tmain(int argc, _TCHAR* argv[])
{
MyProduct *prd;
MyProductFactory::Register<ProductA>("A");
MyProductFactory::Register<ProductB>("B");
prd = MyProductFactory::Create("A");
prd->Iam();
delete prd;
prd = MyProductFactory::Create("B");
prd->Iam();
delete prd;
return 0;
}
It will not compile as is, complaining that the map does not have a valid template type argument for the data type. But if you remove the comments around the 'typename' keyword in the static member definition, everything compiles and works fine... why?
and also, can I make this any better? :)
The standard tries to allow an implementation to parse and
detect as many errors in a template as possible when it reads
the template definition, before any instantiations. C++ is not
context independent, however, and it's very difficult, if not
impossible, to correctly parse statements if you don't know
which symbols are types and which are templates. If the symbol
is dependent (depends on the template parameters in some way),
you have to tell the compiler when it is a type or a template;
otherwise, the compiler must assume that it is something else.
In this case, you're telling the compiler that
AbstractFactory::MyFactoryConstructor names a type,
and not something else.
If, when the template is instantiated, and the compiler can see
to what the symbol is really bound, it turns out that you lied
(e.g. AbstractFactory::MyFactoryConstructor is in fact
an int), then the compiler will get mad at you.
Note too that the fact that the AbstractFactory was defined
before the definition requiring the typedef doesn't change
anything. There could always be an explicit specialization for
the type you're instantiating AbstractFactory on.
The simple reason is that even though you and I looking at the code know that AbstractFactory::MyFactoryConstructor is a type, the compiler doesn't -- or rather, is prohibited by the standard from knowing this. As far as it knows in the first pass of compilation, MyFactoryConstructor -- itself inside a template yet to be fully realized -- could be something else, like a static variable, which isn't allowed as the second template argument to the map, which requires a type. Supplying "typename" permits the compiler to treat it as a type as soon as it is first encountered.