enable_if and constructor with VS2012 - c++

I am trying to conditionally enable a constructor template. With a fully C++11-compliant compiler, I know how to do this using an extra default template argument. However, I need to support VS2012, which has std::enable_if but does not support defaulted function template arguments.
With C++11, I would write the following:
template<typename T>
struct Class
{
template<typename O,
typename = typename std::enable_if<std::is_convertible<O*, T*>::value>::type>
Class(O*) {}
};
I tried the following, but it gives an error C4336 and various follow-up errors:
template<typename T>
struct Class
{
template <typename O>
Class(O*, typename std::enable_if<std::is_convertible<O*, T*>::value>::type *= nullptr)
{
}
};
Is there any way to make this work with VS2012?
Addition:
The usage of the class would be as follows:
struct X { };
struct X2 : X { };
struct Y { };
struct Client
{
Client(Class<X> x) {}
Client(Class<Y> y) {}
};
void test() {
X2* x2;
Client client(x2); // error C2668: ambiguous call to overloaded function
// (without std::enable_if)
}

You are so close to the solution !
template<typename T>
struct Class
{
template <typename O>
Class(O*, typename std::enable_if<std::is_convertible<O*, T*>::value>::type * = nullptr)
{
}
};
Did you spot the difference ? *= inside the parameter list was parsed as the multiplication/assignment operator, not as a pointer type followed by a default argument. Hence, syntax errors.
This is because the C++ parser is specified to consume as many characters as possible when it forms a token (the so-called Maximum Munch Rule). Adding a space splits it into two separate tokens, as intended.

I am afraid, you'd have to use a helper construct function (I didn't find a way around it). But something like this should work:
#include <type_traits>
template<typename T>
struct Class
{
template<typename O>
Class(O* o) { construct(o, std::integral_constant<bool, std::is_convertible<T*, O*>::value>()); }
template<class O>
void construct(O*, std::true_type ) { /* convertible */ }
template<class O>
void construct(O*, ... ) { /* not convertible */ }
};
struct X { };
struct Y : public X { };
void check() {
X x;
int i;
Class<Y> cl(&x);
Class<Y> cl1(&i);
}

Since C++11, you can also use delegating constructors to do that:
template<typename T>
class Class {
template<typename O>
Class(O *o, std::true_type) {}
template<typename O>
Class(O *o, std::false_type) {}
public:
template<typename O>
Class(O *o): Class(o, typename std::is_convertible<O*, T*>::type) {}
};
The basic idea is the one of tag dispatching and maybe it works fine also with VS2012.
See here for further details.

Related

How to reduce recursive variadic inheritance code bloat?

Let's say I want to create a variadic interface with different overloads for the structs A,B,C:
struct A{};
struct B{};
struct C{};
template <typename ... Ts>
class Base;
template <typename T>
class Base<T>{
public:
virtual void visit(const T& t) const
{
// default implementation
}
};
template<typename T, typename ... Ts>
class Base<T, Ts...>: Base<T>, Base<Ts...>{
public:
using Base<T>::visit;
using Base<Ts...>::visit;
};
int main()
{
A a;
B b;
auto base = Base<A,B,C>{};
auto base2 = Base<A,C,B>{};
base.visit(a);
base2.visit(b);
}
Now funtionally Base<A,B,C> is identical to Base<A,C,B> but the compiler still generates the different combinations. Of course with more template parameters it gets worse.
I assume there is some meta programming magic which can cut this code bloat down.
One solution might be to define template<typename T, typename U> Base<T,U> in a way that it checks if Base<U,T> already exists. This could reduce at least some combinations and can probably be done by hand for triplets as well. But I am missing some meta programming magic and hoping for a more general approach.
Edit:
I would like to have the variadic Interface for a (simplified) use case like that:
class Implementation:public Base<A,B,C>
{
public:
void visit(const A& a) const
{
std::cout <<"Special implementation for type A";
}
void visit(const B& a) const
{
std::cout <<"Special implementation for type B";
}
// Fall back to all other types.
};
using BaseInterface = Base<A,B,C>;
void do_visit(const BaseInterface& v)
{
v.visit(A{});
v.visit(B{});
v.visit(C{});
}
int main()
{
std::unique_ptr<BaseInterface> v= std::make_unique<Implementation>();
do_visit(*v);
}
The reason why I want to do this is that there could be potentially a lot of types A,B,C,... and I want to avoid code duplication to define the overload for each type.
Base<A, B, C> instantiates Base<A>, Base<B, C>, Base<B>, Base<C>
and
Base<A, C, B> instantiates Base<A>, Base<C, B>, Base<B>, Base<C>
Whereas final nodes are needed, intermediate nodes increase the bloat.
You can mitigate that issue with:
template <typename T>
class BaseLeaf
{
public:
virtual ~BaseLeaf() = default;
virtual void visit(const T& t) const
{
// default implementation
}
};
template <typename... Ts>
class Base : public BaseLeaf<Ts>...
{
public:
using BaseLeaf<Ts>::visit...;
};
Demo
Base<A,B,C> and Base<A,C,B> are still different types.
To be able to have same type, they should alias to the same type, and for that, ordering Ts... should be done in a way or another.
Looks like the member function should be a template rather than the class.
struct A{};
struct B{};
struct C{};
class Foo {
public:
template<typename T>
void visit(const T& t) const
{
// default implementation
}
};
int main()
{
A a;
B b;
auto foo = Foo{};
foo.visit(a);
foo.visit(b);
}
https://godbolt.org/z/nTrYY6qcn
I'm not sure what is your aim, since there is not enough details. With current information I think this is best solution (there is a also a lambda which can address issue too).
It's necessary to enforce some sort of discipline on the order of template parameters. You can do this with a template variable and a few static_asserts:
#include <type_traits>
template <typename ... Ts>
class Base;
struct A
{
};
struct B
{
};
struct C
{
};
struct D
{
};
template <class T>
static constexpr int visit_sequence_v = -1;
template <>
constexpr int visit_sequence_v<A> = 0;
template <>
constexpr int visit_sequence_v<B> = 1;
template <>
constexpr int visit_sequence_v<C> = 2;
template <typename T>
class Base<T>{
public:
static_assert(visit_sequence_v<T> >= 0, "specialize visit_sequence_v for this type");
virtual void visit(const T& t) const
{
// do nothing by default
}
};
template<typename T1, typename T2>
class Base<T1, T2>: Base<T1>, Base<T2>
{
public:
static_assert(std::is_same_v<T1, T2> || visit_sequence_v<T1> < visit_sequence_v<T2>);
using Base<T1>::visit;
using Base<T2>::visit;
};
template<typename T1, typename T2, typename ... Ts>
class Base<T1, T2, Ts...>: Base<T1>, Base<T2, Ts...>
{
public:
static_assert(std::is_same_v<T1, T2> || visit_sequence_v<T1> < visit_sequence_v<T2>);
using Base<T1>::visit;
using Base<Ts...>::visit;
};
int main()
{
A a;
B b;
auto base = Base<A,B,C>{};
//auto base2 = Base<A,C,B>{}; // static_assert fails
//auto base3 = Base<A,B,C,D>{}; // forgot to specialize
base.visit(a);
}
Notice the point here is to cause a compilation failure if you get the order wrong. If someone has the chops to do a compile-time sort it may be possible to cobble up a traits class (or a template function that you can use decltype on the return type) that selects an implementation of Base in the correct order.
One alternative is to declare a full specialization of Base for every individual type that can be visited (supplying a "default implementation" for visit) and declare a static constexpr visit_sequence within each specialzation.
A problem inherent in your method is that in the case of multiple inheritance, visit can be ambiguous:
struct E: public A, public B
{
};
// 5 MiNuTES LATeR...
DescendantOfBase<A, B> a_b;
E e;
a_b.visit (e); // ambiguous

How to make base class's operators visible with variadic number of base classes (please see code below)?

What is the best way to expose operators from base class like the following code is trying to do. I suppose with one or two base classes we'd use using syntax, but with a variadic number of base classes, is something like using Base<Ts>::operator=...; possible?
template <typename T, typename Derived>
class varU
{
protected:
varU() = default;
Derived& operator=(T val)
{
static_cast<Derived*>(this)->set(val);
return *static_cast<Derived*>(this);
}
};
template <typename ...Ts>
class var : public varU<Ts, var<Ts...>>...
{
// using varU<Ts, var<Ts...>>::operator=...; // Something like this?
private:
template <typename T>
void set(const T& v)
{
}
};
EDIT:
Seems like using Base<Ts>::operator=... is indeed the correct syntax which I was looking for in C++17. I was using the wrong standard version and expecting C++17. Since this was my guess, I didn't dig deep.
I'm not exactly sure, what you want to achieve with your code, so perhaps you want to go a bit more into detail in your question.
But regarding your question in the code-comment, the answer is yes, it's possible in C++17.
If you actually want to use your operators, you also have to declare the varU class a friend of var:
The following compiles on gcc and clang:
template <typename T, typename Derived>
class varU
{
protected:
varU() = default;
Derived& operator=(T val)
{
static_cast<Derived*>(this)->set(val);
return *static_cast<Derived*>(this);
}
};
template <typename ...Ts>
class var : public varU<Ts, var<Ts...>>...
{
template <typename T, typename Derived>
friend class varU;
public:
using varU<Ts, var<Ts...>>::operator=...; // Something like this?
private:
template <typename T>
void set(const T& v)
{
}
};
int main() {
var<int, float> x;
x = 5;
x = 5.f;
return 0;
}
See live code here.

C++ std::enable_if fallback?

I'm setting up a variadic template function to be able to call various function overloads on a specific series of classes. So far, I've been able to "break" the compilation when an unsupported class is passed to the function, but I'd like to be able to provide a valid fallback to handle the "unsupported" scenario at runtime.
The current implementation goes like this :
struct ClassA {};
struct ClassB {};
struct ClassC {};
template<typename T> struct is_my_class : std::false_type {};
template<> struct is_my_class<ClassA> : std::true_type {};
template<> struct is_my_class<ClassB> : std::true_type {};
template<typename T>
constexpr bool is_my_class_v = is_my_class<T>::value;
void runOverload(ClassA c) { printf("ClassA overload\n"); }
void runOverload(ClassB c) { printf("ClassB overload\n"); }
template<typename T, typename = std::enable_if_t<is_my_class_v<T>>>
void run(T myClass)
{
runOverload(myClass);
};
template<typename T, typename... Ts>
void run(T myClass, Ts... classesLeft)
{
run(myClass);
run(classesLeft...);
};
int main()
{
ClassA a;
ClassB b;
ClassC c;
run(a, b); // works
run(c); // does not compile
}
Here, the two most promising (but still failing) attempts I've made to have a fallback for run:
1 - Adding a simple ! in front of is_my_class<T>, giving me the following error : error C2995: 'void run(T)': function template has already been defined
template<typename T, typename = std::enable_if_t<!is_my_class_v<T>>>
void run(T myClass)
{
printf("Not supported\n");
};
2 - Making a more "primary" template definition, which yields a sad but obvious : error C2668: 'run': ambiguous call to overloaded function
template<typename T>
void run(T myClass)
{
printf("Not supported\n");
};
EDIT
I forgot to specify I was looking for a solution also compatible with C++11/14
You could avoid enable_if entirely, and just use a compile-time if to to decide what code to execute:
template<typename T>
void run(T myClass)
{
if constexpr (is_my_class_v<T>)
runOverload(myClass);
else
printf("Not supported\n");
}
Here's a demo.
Even though I'd recommend #cigien 's solution if c++17 is avaiable, I would like to add, that the ambiguity problem can be mitigated pre c++17 by changing the type of the enable_if template argument, and hence changing the signature of the "fallback function". The following code should work fine:
template<typename T, std::enable_if_t<!is_my_class_v<T>, int> = 0>
//template<typename T>
void run(T myClass) {
printf("error\n");
};
Full code available on CompilerExplorer, tested on GCC and Clang trunk.
I'd also like to add, that in all use cases I can imagine, it is better to have a compile time error (which you could for instance achieve by using a static assertion instead of SFINAE).
Here you can read about why the function delcaration is not ambiguous, even when using two "ints" as template arguments.
I wrote following code and it works. I think you just messed up with syntax of SFINAE.
#include <iostream>
#include <type_traits>
struct ClassA {};
struct ClassB {};
struct ClassC {};
template<typename T> struct is_my_class : std::false_type {};
template<> struct is_my_class<ClassA> : std::true_type {};
template<> struct is_my_class<ClassB> : std::true_type {};
template<typename T>
constexpr bool is_my_class_v = is_my_class<T>::value;
void runOverload(ClassA c) { printf("ClassA overload\n"); }
void runOverload(ClassB c) { printf("ClassB overload\n"); }
template<typename T, std::enable_if_t<is_my_class_v<T>,int> = 0>
void run(T myClass)
{
runOverload(myClass);
};
template<typename T, std::enable_if_t<not is_my_class_v<T>,int> = 0>
void run(T myClass)
{
printf("Not supported\n");
};
// wrote an extra SFINEA here to ensure that Ts aren't empty - else it might be an ODR issue despite the fact that it compiles
template<typename T, typename... Ts, std::enable_if_t<sizeof...(Ts) != 0,int> = 0>
void run(T myClass, Ts... classesLeft)
{
run(myClass);
run(classesLeft...);
};
int main()
{
ClassA a;
ClassB b;
ClassC c;
run(a, b);
run(c);
}
It prints
ClassA overload
ClassB overload
Not supported
Have a fallback runOverload template
template<typename T>
void runOverload(T myClass)
{
printf("Not supported\n");
};

Specializing a template for a container of type T

Given I have a template setup to do something on a type such as...
template<typename T>
class SimpleTemplate
{
private:
T m_obj;
public:
void operator()() { m_obj.DoSomething(); }
};
And I want to handle the case where I have a collection of type T the same way. I currently have a template setup like so for a vector...
template<typename T>
class SimpleTemplate<std::vector<T>>
{
private:
std::vector<T> m_collection;
public:
void operator()()
{
for (auto&& obj : m_collection) obj.DoSomething();
}
};
Now I want to also support sets, unordered_sets and so on. I could write a template for each collection but I feel like this should be a perfect job for a template, only I can't figure out how it should be written, or even if it can be?
Can I do something like template<typename C<T>>?
As mentioned by Geoffroy, you can use a trait to detect whether T can be iterated over. You then use this to select the correct specialization.
So start off with the "is_iterable" trait shown by Jarod42 here:
// Code by Jarod42 (https://stackoverflow.com/a/29634934).
#include <iterator>
#include <type_traits>
namespace detail
{
// To allow ADL with custom begin/end
using std::begin;
using std::end;
template <typename T>
auto is_iterable_impl(int)
-> decltype (
begin(std::declval<T&>()) != end(std::declval<T&>()), // begin/end and operator !=
void(), // Handle evil operator ,
++std::declval<decltype(begin(std::declval<T&>()))&>(), // operator ++
void(*begin(std::declval<T&>())), // operator*
std::true_type{});
template <typename T>
std::false_type is_iterable_impl(...);
}
template <typename T>
using is_iterable = decltype(detail::is_iterable_impl<T>(0));
This gives you an is_iterable<T> trait which inherits from either std::true_type or std::false_type. Now use this with SFINAE to create two specializations:
template <class T, bool = is_iterable<T>::value>
class SimpleTemplate;
template <class T>
class SimpleTemplate<T, false> {
private:
T m_obj;
public:
SimpleTemplate (T obj) : m_obj(std::move(obj)) { }
void operator() () { m_obj.DoSomething(); }
};
template <class T>
class SimpleTemplate<T, true> {
private:
T m_collection;
public:
SimpleTemplate (T obj) : m_collection(std::move(obj)) { }
void operator() () {
for (auto && obj : m_collection) { obj.DoSomething(); }
}
};
Since both partial specializations are mutually exclusive for any given T, you won't get any errors about ambiguity.
Edit: Changed 2nd template argument into a bool instead of class. This makes it simple to fully specialize it in case the default behavior is unwanted.
E.g. for std::string, which for which is_iterable is true, simply do the following. Note that I added constructors to SimpleTemplate, I couldn't get the full specialization to inherit the base class' constructor otherwise.
template <>
class SimpleTemplate<std::string, true>
: public SimpleTemplate<std::string, false> {
// Inherit constructor.
using base = SimpleTemplate<std::string, false>;
using base::base;
};
Now I want to also support sets, unordered_sets and so on. I could write a template for each collection but I feel like this should be a perfect job for a template, only I can't figure out how it should be written, or even if it can be
Maybe you can use a template-template parameter
template <template <typename...> class C, typename... Ts>
class SimpleTemplate<C<Ts...>>
{
private:
C<Ts...> m_collection;
public:
void operator()()
{
for (auto&& obj : m_collection) obj.DoSomething();
}
};
This should intercept std::(unordered_)(multi)set, std::vector, std::deque, etc.
Unfortunately doesn't intercept std::array, because it's second template parameter is a value, not a type.

Parent template argument deduction in nested class constructor

I am trying to write the "promotion" constructor of a nested class that can deduce the parent class template. It works fine for the parent class, but not in the nested class. Here is a code example.
template <class T>
struct potato {
struct baked {
template <class O>
baked(const typename potato<O>::baked& p)
: something(static_cast<T>(p.something)) {
}
baked() = default;
T something;
};
template <class O>
potato(const potato<O>& p)
: mybaked(p.mybaked) {
}
potato() = default;
baked mybaked;
};
int main(int, char**) {
potato<int> potato1;
potato<short> potato2(potato1);
}
Is this legal?
Various compilers output various errors. Clang has the most readable in my mind. It states :
candidate template ignored: couldn't infer template argument 'O'
https://godbolt.org/z/y_IZiE
So I'm guessing either I've messed up the signature, or this isn't a c++ supported feature.
I don't know of any way to deduce the template argument T for a baked's parent potato<T>. You can know T using decltype(p.something) but that doesn't seem to help solve the problem with calling the constructor. One workaround is to change baked's constructor to take any O and assume it has a something :
struct baked {
template <class O>
baked(const O & p) : something(static_cast<T>(p.something))
{ }
baked() = default;
T something;
};
This will work but it is less type-safe than your original code seems to intend. One workaround for that problem could be to introduce a static_assert that checks that O is actually a potato<U>::baked :
#include <type_traits>
template <class T>
struct potato {
struct baked {
template <class O>
baked(const O & p) : something(static_cast<T>(p.something))
{
using t_parent = potato<decltype(p.something)>;
static_assert(std::is_same<O, typename t_parent::baked>::value, "Not a baked potato!");
}
baked() = default;
T something;
};
template <class O>
potato(const potato<O>& p)
: mybaked(p.mybaked) {
}
potato() = default;
baked mybaked;
};
This should compile fine for the intended usage but fail with "Not a baked potato!" if you try to pass anything else with a something. This would fail :
struct foo {
int something = 0;
};
int main(int, char**) {
foo bar;
potato<int>::baked baz(bar); // Error: Not a baked potato!
}
As state by the compiler O is not deducible from const typename potato<O>::baked& (on left side of ::).
You have several workarounds:
Move baked outside parent and make it template:
// Possibly in namespace details
template <typename T>
struct baked_impl {
template <class O>
baked_impl(const typename baked_impl<O>& p)
: something(static_cast<T>(p.something)) {
}
baked_impl() = default;
T something;
};
template <class T>
struct potato {
using baked = baked_impl<T>;
// ...
};
Add parent info in baked and use SFINAE:
template <class T> struct potato;
// traits for SFINAE
template <class T> struct is_potato : std::false_type {};
template <class T> struct is_potato<potato<T>> : std::true_type {};
template <class T>
struct potato {
using value_type = T;
struct baked {
using parent = potato;
template <class O, std::enable_if_t<is_potato<typename O::parent>::value, int> = 0>
baked(const O& p)
: something(static_cast<typename O::parent::value_type>(p.something)) {
}
baked() = default;
T something;
};
// ...
};