CRTP doesn't really work for types - I've never worked out why to my own satisfaction. You can get around the problem by wrapping up the identifier in a function:
template <class derived> class base
{
private:
unsigned identifier()
{
return static_cast<derived*>(this)->identifier();
}
};
class derived : base<derived>
{
private:
unsigned identifier()
{
return 37;
}
};
Then instead of switching/branching on the value in the enum in the base class you can switch on the result of the identifier() function. Of course as you want a variable state you won't be able to use a constant as I have in the example but you can introduce complications to taste.
Cheers,
Ash
PS: The return value from the function doesn't have to be an int, it can be just about anything that makes sense in the context of the base class.
PPS: One of the things you said you wanted was to be able to write:
base::function( derived::type t );
and have things routed to the right place. You can do that with a template member function:
#include <iostream>
template<class derived>
class base
{
public:
template <typename T>
int return_value_for_squared( T t )
{
int n = static_cast<derived *>(this)->return_value_for( t );
return n * n;
}
};
class derived : public base<derived>
{
public:
enum values { A, B, C };
int return_value_for( values v )
{
return v;
}
};
int main()
try
{
derived d;
std::cout << d.return_value_for_squared( derived::C ) << std::endl;
}
catch( std::exception &e )
{
std::cout << "Something went wrong: " << e.what() << std::endl;
}
catch( ... )
{
std::cout << "Something went wrong, no idea what!" << std::endl;
}