Mixing aliases and template specializations - c++

I'm trying to find the best method to have a kind of "object" that can be either specialized or "linked" to another type.
For instance you cannot specialize a class to make it become a simple int, and you cannot use the keyword using to specialize classes.
My solution is the following:
template<class Category, Category code>
struct AImpl
{};
template<class Category, Category code>
struct AHelper
{
using type = AImpl<Category, code>;
};
template<class Category, Category code>
using A = typename AHelper<Category, code>::type;
template<int code>
void doSomething(A<int, code> object)
{
}
template<>
struct AImpl<int, 5>
{
double a;
};
template<>
struct AImpl<int, 6>
{
int b;
double c;
};
template<>
struct AHelper<int, 7>
{
using type = int;
};
template<class Category, Category code>
struct Alternative {};
template<int code>
void doSomethingAlternative(Alternative<int, code> object)
{
}
This works but you need to specify the code parameter in doSomething, and I would like to avoid that.
For instance:
A<int,7> a7; // This is equivalent to int
a7 = 4;
A<int, 5> a5; // This is equivalent to AImpl<int,5>
a5.a = 33.22;
doSomething(a5); // This does not compile
doSomething<5>(a5); // This compiles but is bulky
Alternative<int,0> alt0;
doSomethingAlternative(alt0); // This compiles and is not bulky
// but you're forced to use class
// specializations only
Is there a way to achieve what I want? It's ok to change both doSomething or the A implementation.

If you are trying to customize the behavior of doSomething based on the type it is called with, you cannot have the compiler deducing stuff from AHelpr::type (as previously answered). But you can tell it what it needs to know by providing a customization point in the form of traits. For instance:
template<typename T>
void doSomething(T& object)
{
auto code = SmthTriats<T>::code;
}
This is highly extendable given the ability to specialize SmthTriats:
template<typename> struct SmthTriats;
template<typename Category, Category code_>
struct SmthTriats<AImpl<Category, code_>> {
static constexpr auto code = code_;
};
template<>
struct SmthTriats<int> {
static constexpr auto code = 7;
};
A traits class allows for customization outside your module too. Client code need only specialize SmthTriats with their own type, and so long as they respect the contract you laid out with your trait, your code will work for them.

Related

Optionally activating a constructor in a templated class

Let's suppose we have this class:
class MyEnumClass
{
public:
enum Type
{
Example0,
Count
};
using EnumType = Type;
};
And this one.
class MyEnumClass2
{
public:
enum Type2
{
Example0,
Count
};
};
And we want to handle something related to it in a different class. But this class also supports other different than MyEnumClass classes, MyEnumClass2 is included too and have not same members. The classes are not meant to be touched at all. So I want it to be copy constructible from its instantiable classes:
template<typename T, typename U>
class EnumClassHandler
{
public:
EnumClassHandler() : value(0) {}
// Here want to make an optional copy constructor
EnumClassHandler(const T::EnumType& value)
{
// Do whatever
}
// This class should also be supported
EnumClassHandler(const T::Type2& value)
{
//Do whatever
}
U value;
};
I would like this EnumClassHandler to support this:
typedef EnumClassHandler<MyEnumClass, uint32_t> MyEnumClassHandler;
typedef EnumClassHandler<MyEnumClass2, uint32_t> MyEnumClass2Handler;
int main()
{
MyEnumClassHandler example = MyEnumClass::Example0;
MyEnumClass2Handler example2 = MyEnumClass2::Example0;
}
Here is the wandbox code reflecting the problem, which is that fails on instantiating non supported constructors for different classes.
How can I make EnumClassHandler support optionally copy constructible for those, and a bunch of similar to MyEnumClass and MyEnumClass2 classes(so modifying those internally is not allowed), in c++14?
To enable the constructor only for the respective T::EnumType or T::Type2 you can do this:
template<typename T, typename U>
class EnumClassHandler
{
public:
EnumClassHandler() : value(0) {}
// only viable when T has T::EnumType
template <typename W = T>
EnumClassHandler(const typename W::EnumType& value)
{
//Do whatever
}
// only viable when T has T::Type2
template <typename W = T>
EnumClassHandler(const typename W::Type2& value)
{
//Do whatever
}
U value;
};
This will make your code work, while this
MyEnumClass2Handler example3 = MyEnumClass::Example0;
results in error:
<source>:56:47: error: conversion from 'MyEnumClass::Type' to non-scalar type 'MyEnumClass2Handler' {aka 'EnumClassHandler<MyEnumClass2, unsigned int>'} requested
56 | MyEnumClass2Handler example3 = MyEnumClass::Example0;
| ~~~~~~~~~~~~~^~~~~~~~
Live Demo.
PS: If possible I would rather add an EnumType alias to each MyEnumClassX to keep that complexity out of the EnumClassHandler. If this isnt feasible, I would use a type trait:
template <typename MYENUMCLASS>
struct enum_type_from_myenumclass {
using type = typename MYENUMCLASS::EnumType;
};
You can specialize it for each MyEnumClass that does not have the EnumType member alias:
template <>
struct enum_type_from_myenumclass<MyEnumClass2> {
using type = typename MyEnumClass2::Type2;
};
// ... and similar for others ...
Then the EnumClassHandler only needs to use enum_type_from_myenumclass<T>::type and doesn't need to care about the differently named aliases.
Live Demo

Derive template arguments from other argument but keep intelli sense

Let's assume I have the following classes:
template<typename A> class Foo { ... };
template<typename A, typename B = Foo<A>> class Bar { ... };
Bar is virtual, and it can be derived with many different arguments for A and B. The template's purpose is to provide intelli-sense for the derivations. I do not want to use interfaces for A and B since they have nothing in common. Also, it would cause a lot of unnecessary casting.
The problem is that I also want to provide various algorithms that use Bar, some generic ones, and some are specialized. Something I tried looks like this:
template<typename A, typename B = Foo<A>, typename BarType = Bar<A, B>>
class Algorithm
{
void doWork(BarType& bar) { ... };
};
What I want to do is pass a derivation from Bar to the Algorithm, and it should automatically detect the arguments A and B. For example:
class BarDerivation : Bar<int, Foo<int>> { ... };
Algorithm<BarDerivation> alg;
This answer provides a solution using type-traits, the problem is that Algorithm would lose the information that BarType is from type Bar.
I'm not certain if what I'm doing is the best approach for what I want to achieve. So is there a solution that solves my problem, or are there better approaches?
Simpler would be to add alias in Foo/Bar:
template<typename A> class Foo { using type = A; };
template<typename A, typename B = Foo<A>> class Bar { using T1 = A; using T2 = B; };
class Derived : Bar<int, Foo<float>> { /*...*/ };
template <typename BarType>
class Algorithm
{
using A = typename BarType::T1;
using B = typename BarType::T2;
void doWork(BarType& bar) { ... };
};

Associating enums with template classes at compile time

I have a template class as below:
template<typename A> struct TaskInfo{
typedef A _A;
static void bar(A a){blah blah...} };
template <typename TaskInfo> class Task {
typedef typename TaskInfo::_A A;
bar(A a){
blah blah...
TaskInfo::bar(a);
}
}
and I have an object that has a collection of these classes:
using TaskInfoX= TaskInfo<int>; //ignore the bar implementation for the time being.
using TaskInfoY= TaskInfo<double>;
class TaskCollection(){
TaskCollection(){
auto Task1=new Task<TaskInfoX>;
auto Task2=new Task<TaskInfoY>;
Register(Task1);
Register(Task2);
}
Register(...);
}
I want to know if it is possible to define an enum list:
enum TaskEnum
{
Etask1,
Etask2
};
and a function getTask such that in my app I can have:
int main {
TaskCollection collection;
int testInt;
double testDouble;
collection.getTask(Etask1)->bar(testInt);
//collection.getTask(Etask1)->bar(testDouble); //want compile error.
collection.getTask(Etask2)->bar(testDouble);
}
I know that I can have CRTP or the virtual inheritance equivalent that allows me to pass variadic arguments for bar() but I want to have type checking on the parameters of the bar function at compile time. Is this impossible in C++?
Update: Apologise for the typo. That was meant to be: getTask(task1). basically the outside world doesn't know about the underlying structure of the tasks and only knows them based on their public enum keys. Also note that in general there would be additional tasks potentially reusing the typeInfoX parameter.
First, to have error if type is not an exact match, you may use the following:
template <typename T>
class Task
{
public:
using type = typename T::type;
void bar(type a) { T::bar(a); }
template <typename U>
std::enable_if_t<!std::is_same<std::decay_t<U>, type>::value>
bar(U&&) = delete;
};
Then, with some helpers:
template <TaskEnum> struct TaskMap;
template <> struct TaskMap<Etask1> { using type = Task<TaskInfoX>; };
template <> struct TaskMap<Etask2> { using type = Task<TaskInfoY>; };
Your collection could be something like:
class TaskCollection
{
public:
Task<TaskInfoX> taskX;
Task<TaskInfoY> taskY;
template <TaskEnum E>
typename TaskMap<E>::type&
getTask();
};
template <>
Task<TaskInfoX>& TaskCollection::getTask<Etask1>() { return taskX; }
template <>
Task<TaskInfoY>& TaskCollection::getTask<Etask2>() { return taskY; }
With final usage:
collection.getTask<Etask1>().bar(testInt);
collection.getTask<Etask1>().bar(testDouble);//error:call to deleted member function 'bar'
collection.getTask<Etask2>().bar(testDouble);
Demo
You can always template a concrete class with primitives. So instead of:
using TaskInfoX= TaskInfo<int>;
using TaskInfoY= TaskInfo<double>;
you can just have
template<> class Task<TaskEnum::Task1> : public TaskInfo<int>{}
template<> class Task<TaskEnum::Task2> : public TaskInfo<double>{}
and then define a template function:
template<TaskEnum taskE>
Task<taskE>* getTask() {}
You will need to derive template class Task from a base class so you can put it in a map, and you should define a map
std::map<TaskEnum,TaskBase*> taskMap;
and in getTask you can just do a static cast:
static_cast<Task<taskE>* >(taskBasePtr);
I think std::tuple is what you need:
auto my_tuple = std::make_tuple(Task<TaskInfoX>(), Task<TaskInfoY>());
std::get<Task<TaskInfoX>>(my_tuple).bar(12);
// actually, this is not an error because double can be convert to int
std::get<Task<TaskInfoX>>(my_tuple).bar(12.323);
Given the way Task1 and Task2 are stored in your TaskCollection class, I cant see an obvious way to implement getTask as a template, but you can overload it.
class TaskCollection
{
//...
Task<TaskInfoX> GetTask(Task<TaskInfoX> task)
{
return Task1;
}
Task<TaskInfoY> GetTask(Task<TaskInfoY> task)
{
return Task2;
}
};
If your real case works in with double and int then you need to supress the conversion from double to int in order to achieve this compile-time error...
//collection.getTask(Task1)->bar(testDouble); //want compile error.
one way to do this is to declare but not define a template version of bar in your TaskInfo
template<typename A> struct TaskInfo
{
static void bar(A a){blah blah...}
template<typename T> static void bar(T a); // deliberately not defined
//...
};
you still define your existing bar function for the type you do want to handle, but now, in the case that you want to fail, the compiler will try to call the template version of bar (with T as a double) in preference to calling the int version with a conversion from double to int. The resulting error in VS2015 is
error LNK2019: unresolved external symbol "public: static void __thiscall C::bar(double)
but if no code tries to call it then it doesn't matter that it is not defined an there is no error.
(It wasn't clear to me what the question was regarding the enum)

set public/private on template function for some certain template parameter

Is it possible to make a certain template function have 2 accessibility level for some certain template parameter? (via splitting into 2 functions?)
class B{
enum ENU{
T0,T1,T2
}
template<ENU T=T0> someType f(){ ... } //want T1,T2 = public, T0 = private
};
Current usage (the solution should not change it):-
B b;
int aa=b.f<T0>(); //should fail
std::string bb=b.f<T1>();// should ok
Edit: B has a lot of functions like this.
Here is the full code (just in case someone want to edit or use) https://ideone.com/ryNCml.
I doubt what you are trying to do is possible, as specializing functions on a value ain't allowed in C++.
Though if you don't need enumerations, you could write something similar:
class B {
public:
struct T0{};
struct T1{};
struct T2{};
template<typename T> void f(T, ...) {
static_assert(std::is_same_v<T, T1> || std::is_same_v<T, T2>);
}
private:
void f(T0, ...) {}
};
int main(int argc, char **argv) {
B b{};
b.f(T1{}); // Should compile
b.f(T0{}); // Should not compile
}
If you would use the same function implementation, you can either forward this to a common method, or simply put T0 private.
Alternatively, you could make use of a proxy object which could convert the value, though I'm not sure if this is standard C++ of an extension of the compiler I'm familiar with:
class B {
public:
enum class T { //< Strong typed!
T0,
T1,
T2
}
template <T t>
struct TWrapper {};
template <T ActualT>
void f(..., TWrapper<ActualT> tw = TWrapper<ActualT>{});
private:
template <>
struct TWrapper<T0> {};
}
As far as I can understand, you want to forbid the use of T0 as a template parameter while invoking member method f.
To do that, you can use either std::enable_if or a static_assert.
It follows a minimal, working example:
#include<type_traits>
class B {
public:
enum ENU { T0,T1,T2 };
template<ENU T>
std::enable_if_t<(T==T1||T==T2),int>
f() { return 42; }
template<ENU T>
int g(){
static_assert(T==T1||T==T2, "not allowed");
return 42;
}
};
int main() {
B b;
b.f<B::T1>();
// It doesn't work
//b.f<B::T0>();
b.g<B::T1>();
// It doesn't work
//b.g<B::T0>();
}
Given you want to support only a finite set of template arguments, I would write three functions which are not template functions, and give them the right visibility. Then make them delegate to a private template function which does the work. This would look like:
class B{
public:
enum ENU{
T0,T1,T2
}
private:
template<ENU T=T0> int f(){
std::cout<<"In enum "<<T<<std::endl;
return 0;
}
protected:
someType fT0() { return f<T0>(); }
public:
someType fT1() { return f<T1>(); }
someType fT2() { return f<T2>(); }
};
Contrary to your requirements, the usage changes - but this is often the simplest approach:
B b;
int aa=b.fT0(); // fails
int bb=b.fT1();// ok
Alternatively, you can make the template be public, but give it a dummy argument (with a default), and make the type of the dummy argument depend on the template parameter (via traits). If the type of the dummy is a private class, the template will only be callable by a member.
template <ENU T>
struct protection_traits;
class B{
friend class protection_traits<T0>; // So it has access to Protected.
protected:
struct Protected{};
public:
struct Public{};
enum ENU{
T0,T1,T2
}
template<ENU T=T0> int f( typename protection_traits<T>::type = {})
{ std::cout<<"In enum "<<T<<std::endl; }
};
template <ENU T>
struct protection_traits
{
typedef B::Public type; // Default to public
};
template<>
struct protection_traits<T0>
{
typedef B::Protected type; // But T0 uses Protected
};
Usage:
B b;
int aa=b.f<T0>(); // fails (no access to B::Protected)
int bb=b.f<T1>(); // ok
Note: This latter solution hasn't been fed to a compiler. There will be typos.

How do I define / specialize a type_trait in class scope?

I have the following situation:
My problem revolves around using strongly typed enum classes as flags (just as in C# with the Flags-Attribute). I know this is not the way enum classes were meant to be used in the first place, but that it not the point of this question.
I have defined several operators and functions to use on these enum classes, and a custom type trait to distinguish normal enums from Flag-enums. Here's an example:
// Default type_trait which disables the following operators
template <typename T> struct is_flags : std::false_type {};
// Example operator to use enum class as flags
template <typename T>
std::enable_if_t<std::is_enum<T>::value && is_flags<T>::value, T&>
operator|=(T &t1, const T t2)
{
return t1 = static_cast<T>(static_cast<std::underlying_type_t<T>>(t1) |
static_cast<std::underlying_type_t<T>>(t2));
};
Now if I define any enum class i can do the following:
enum class Foo { A = 1, B = 2 };
enum class Bar { A = 1, B = 2 };
// Declare "Bar" to be useable like Flags
template <> struct is_flags<Bar> : std::true_type {};
void test()
{
Foo f;
Bar b;
f |= Foo::A; // Doesn't compile, no operator |=
b |= Bar::A; // Compiles, type_trait enables the operator
}
The above code works fine and using a macro for the template specialization it almost looks like the very convenient C# Flags-Attribute.
However, when the enum class is not defined in namespace scope, I run into an issue:
struct X
{
enum class Bar { A = 1, B = 2 };
// Following line gives: C3412: Cannot specialize template in current scope
template <> struct is_flags<Bar> : std::true_type {};
}
The type trait cannot be specialized here. I would need to define the trait outside of X, which is possible, but separates the "Flag-Attribute" from the enum declaration. It would be so nice to use this in our code since flags are used all over the place but in a rather old-fashioned manner (int + #define). All solutions to this problem I have found so far focus on classes instead of enums, where the solution is much simpler, since I can define the trait as a member of the class itself. Enums, however, cannot inherit, contain typedefs or whatever might be needed to differentiate a certain enum class from another.
So is there any possibility to define some kind of trait in a class-scope which can be used in global namespace scope to recognize special enum class-types?
EDIT: I should add that I'm using Visual Studio 2013.
UPDATE: Thanks for the answers, the tag-solution worked really well, although I had to make a subtle change (making it even more simple in the process). I'm now using this custom type trait:
template <typename T>
struct is_flags
{
private:
template <typename U> static std::true_type check(decltype(U::Flags)*);
template <typename> static std::false_type check(...);
typedef decltype(check<T>(0)) result;
public:
static const bool value = std::is_enum<T>::value && result::value;
};
Now, all I need to do is add Flags to the enum class, no matter what scope it's in:
enum class Foo { Flags, A = 0x0001, B = 0x0002 };
See also here for a similar problem and solution.
UPDATE 2: Since Visual Studio 2013 Update 2 this solution will cause compiler crashes when the is_flags trait is applied to ios-base headers. Therefore we are now using a different and cleaner approach, we use a template class which acts as the storage for an enum class and defines all operators on itself without any type-trait magic. The template class can be created implicit with the underlying enum class and explicit with the underlying type. Works a charm and is much less of an enable_if-mess.
You could tag the enumeration itself:
#include <type_traits>
template<typename T>
struct is_flags {
private:
typedef typename std::underlying_type<T>::type integral;
template<integral> struct Wrap {};
template<typename U>
static constexpr std::true_type check(Wrap<integral(U::EnumFlags)>*);
template<typename>
static constexpr std::false_type check(...);
typedef decltype(check<T>(0)) result;
public:
static constexpr bool value = std::is_enum<T>::value && result::value;
};
namespace Detail {
template <bool>
struct Evaluate;
template <>
struct Evaluate<true> {
template <typename T>
static T apply(T a, T b) { return T(); }
};
}
template <typename T>
T evalueate(T a, T b)
{
return Detail::Evaluate<is_flags<T>::value>::apply(a, b);
}
enum class E{ A = 1, B, C };
struct X {
enum class F{ EnumFlags, A = 1, B, C };
};
int main ()
{
// error: incomplete type ‘Detail::Evaluate<false>’ used in nested name specifier
// evalueate(E::A, E::B);
evalueate(X::F::A, X::F::B);
}
Here's an ugly solution using ADL instead of traits (of course you can hide the ADL inside the trait):
New operator template:
struct my_unique_enum_flag_type;
// Example operator to use enum class as flags
template <typename T>
enable_if_t<std::is_enum<T>::value
&& std::is_same<decltype(is_flags(std::declval<T>())),
my_unique_enum_flag_type>::value, T&>
operator|=(T &t1, const T t2)
{
return t1 = static_cast<T>(static_cast<underlying_type_t<T>>(t1) |
static_cast<underlying_type_t<T>>(t2));
};
Definition of is_flags for Bar:
struct X
{
enum class Bar { A = 1, B = 2 };
friend my_unique_enum_flag_type is_flags(Bar);
};
int main()
{
X::Bar a = X::Bar::A;
a |= X::Bar::B;
}
(preferably, use a more unique name than is_flags for ADL)