Checking if a class has a copy constructor with TMP - c++

I've been attempting a little SFINAE at making a way to determine if a generic type T has a copy constructor I can use. Here is where I currently am.
template <bool statement, typename out>
struct Failable
{
typedef out Type;
};
//This class is only used to insert statements that
//could encounter substitution failure
template <typename O>
struct COPY
{
template <typename T>
typename Failable<true == sizeof(&T::T(const T&)), char>::Type copy(int)
{}
template <typename T>
typename Failable<true, int>::Type copy(...)
{}
};
However, this is also where I'm kinda stuck. &T::T(const T&) is obviously an invalid statement, as we can't provide an argument list with a pointer-to-member, even if a p-t-m-function.
I could always try to specify some sort of void (T::*ptmf)(const T&) = &T::T, and hope it implicitly determines the right overloaded constructor to put into the pointer to member function, but that also implies that Constructors have a specific return type, which I would have to specify.
Does anyone else have any ideas with which I can trek forth? (I also need to apply a similar concept to checking for an assignment operator.)
Thanks in advanced.

You could use std::is_copy_constructible and std::is_assignable for this.

You can do with your code, just need to modify it a little bit.
template <bool statement, typename out>
struct Failable
{
typedef out Type;
};
template <typename O>
struct COPY
{
static O MakeO();
template <typename U> // U and T are the same type
static typename Failable<(sizeof U(MakeO())), char>::Type copy(int);
template <typename U>
static typename Failable<true, int>::Type copy(...);
enum { value = sizeof(char) == sizeof( copy<O>(0) ) };
};

Related

Deduce template parameter from concept

I'm learning templates and concepts. I'm trying to make a concept for types that are derived from a class, but this class is a template.
template<typename T>
struct CAA{};
template<typename T, typename T2>
concept DerivedFromAA = requires() {std::derived_from<CAA<T2>,T>;};
Is it possible to use such concept in a function without having to explicitly tell it the template type of the class? Is my idea wrong on how to define such concept?
template<typename T>
void conceptTestFunc(DerivedFromAA<T> auto& aa)
{
}
//...
CAA<int> aa;
conceptTestFunc<int>(aa); // Without having to tell it "int"
(I'm compiling this with Clang.)
A template is not a type.
So if CAA is a template, then CAA<int> would be a type.
A type can't be derived from a template, only from another type. This means that the check has to be done on the type, not the template.
If you on the other hand want to deduce the inner type of aa, that can be done.
#include <concepts>
template<typename T>
struct CAA{};
template<typename T>
struct CBB{};
template<typename T, typename T2>
concept DerivedFromAA = std::derived_from<CAA<T2>,T>;
template<template <typename> typename Outer, typename T>
requires DerivedFromAA<Outer<T>, T>
void conceptTestFunc(Outer<T>& aa)
{
}
int main() {
CAA<int> aa;
conceptTestFunc(aa);
CBB<int> bb;
conceptTestFunc(bb); // This fails
}
You might do
template<typename T>
concept DerivedFromAA = requires(T t) {[]<typename U>(CAA<U>&){}(t);};
static_assert(DerivedFromAA<CAA<int>>);
Demo
gcc dislikes lambda in requires, so you might create dummy helper function outside.

Using template typename in a nested function template

Alright, I'm struggling with templates. In this question I learned, that it is not possible to pass a type specifier to a function at all, so my next approach is passing the type inside <>.
Imagine a function template foo<U>(), which is member function of a template class A. So if I create an Object A<T> a I can call a.foo<U>() with any type.
How do I have to write an equivalent function template so I can pass a and U like wrappedFoo<U>(a)?
IMPORTANT Needs to be C++98 compliant
You might do the following:
template <typename U, typename T>
XXXX /* See below */
WrappedFoo(/*const*/ A<T>& a)
{
return a.template foo<U>();
}
The hard part is the return type without decltype of C++11.
So if the return type really depends of parameters type, you can create a trait, something like:
template <typename U, typename T>
struct Ret
{
typedef U type;
};
template <typename T> struct Ret<T, A<T> >
struct Ret
{
typedef bool type;
};
And then replace XXXX by typename Ret<U, T>::type

Q: Template class that takes either a normal type or a template template argument

Recently I designed meta-types and the possible operations that would allow compile-time type concatenations:
#include <tuple>
template<template<typename...> typename T>
struct MetaTypeTag
{};
/*variable template helper*/
template<template<typename...> typename T>
constexpr MetaTypeTag<T> meta_type_tag = {};
template<typename T>
struct TypeTag
{};
/*comparison*/
template<typename T>
constexpr bool operator==(TypeTag<T>, TypeTag<T>) { return true; }
template<typename T, typename U>
constexpr bool operator==(TypeTag<T>, TypeTag<U>) { return false; }
/*variable template helper*/
template<typename T>
constexpr TypeTag<T> type_tag = {};
template<template<typename...> typename T, typename... Ts>
constexpr TypeTag<T<Ts...>> combine(MetaTypeTag<T>, TypeTag<Ts>...)
{
return {};
}
int main()
{
constexpr auto combined_tag = combine(meta_type_tag<std::tuple>, type_tag<int>, type_tag<float>);
static_assert(combined_tag == type_tag<std::tuple<int, float>>, "");
}
The std::tuple without template arguments cannot be used as a type, but may still appear in the template template parameter.
Now if we try to go one step further, the question is whether there is any way to unify struct MetaTypeTag and struct TypeTag, since they are both empty classes with one template parameter, or at least it could be possible to use the same variable template type_tag but redirect to a different class depending on the type category? So I would imagine something like this:
template<???>
constexpr auto type_tag = ????{};
//use with 'incomplete type'
type_tag<std::tuple> //MetaTypeTag<std::tuple>
//use with regular type
type_tag<int> //TypeTag<int>
I tried all possible ways - redefinition, explicit specialization, partial specialization, optional template parameters, conditional using alias, but none worked. I had hoped C++17's template<auto> would help, but it turns out that one is for non-type only.
the question is whether there is any way to unify struct MetaTypeTag and struct TypeTag, since they are both empty classes with one template parameter
I don't thinks so.
The best I can imagine to simplify a little (very a little) your code is define a couple of overloaded constexpr function, say getTag()
template <typename T>
auto constexpr getTag ()
{ return TypeTag<T>{}; }
template <template <typename ...> typename T>
auto constexpr getTag ()
{ return MetaTypeTag<T>{}; }
so you can call getTag<T>() where T is either a type or a template.
So you can call combine() as follows
constexpr auto combined_tag
= combine(getTag<std::tuple>(), getTag<int>(), getTag<float>());
But I don't think is a great improvement.

How to use sfinae for selecting constructors?

In template meta programming, one can use SFINAE on the return type to choose a certain template member function, i.e.
template<int N> struct A {
int sum() const noexcept
{ return _sum<N-1>(); }
private:
int _data[N];
template<int I> typename std::enable_if< I,int>::type _sum() const noexcept
{ return _sum<I-1>() + _data[I]; }
template<int I> typename std::enable_if<!I,int>::type _sum() const noexcept
{ return _data[I]; }
};
However, this doesn't work on constructors. Suppose, I want to declare the constructor
template<int N> struct A {
/* ... */
template<int otherN>
explicit(A<otherN> const&); // only sensible if otherN >= N
};
but disallow it for otherN < N.
So, can SFINAE be used here? I'm only interested in solutions which allow automatic template-parameter deduction, so that
A<4> a4{};
A<5> a5{};
A<6> a6{a4}; // doesn't compile
A<3> a3{a5}; // compiles and automatically finds the correct constructor
Note: this is a very simplified example where SFINAE may be overkill and static_assert may suffice. However, I want to know whether I can use SFINAE instead.
You can add a defaulted type argument to the template:
template <int otherN, typename = typename std::enable_if<otherN >= N>::type>
explicit A(A<otherN> const &);
There are many ways to trigger SFINAE, being enable_if just one of them.
First of all:
What is std::enable_if ?
It's just this:
template<bool, class T=void> enable_if{ typedef T type; };
template<class T> enable_if<false,T> {};
template<bool b, class T=void> using enable_if_t = typename enable_f<b,T>::type;
The idea is to make typename enable_if<false>::type to be an error, hence make any template declaration containing it skipped.
So how can this trigger function selection?
Disabling functions
The idea is making the declaration erroneous in some part:
By return type
template<class Type>
std::enable_if_t<cond<Type>::value,Return_type> function(Type);
By a actual parameter
template<class Type>
return_type function(Type param, std::enable_if_t<cond<Type>::value,int> =0)
By a template parameter
template<class Type,
std::enable_if_t<cond<Type>::value,int> =0> //note the space between > and =
return_type function(Type param)
Selecting functions
You can parametrise different alternatives with tricks like this:
tempplate<int N> struct ord: ord<N-1>{};
struct ord<0> {};
template<class T, std::enable_if<condition3, int> =0>
retval func(ord<3>, T param) { ... }
template<class T, std::enable_if<condition2, int> =0>
retval func(ord<2>, T param) { ... }
template<class T, std::enable_if<condition1, int> =0>
retval func(ord<1>, T param) { ... }
template<class T> // default one
retval func(ord<0>, T param) { ... }
// THIS WILL BE THE FUCNTION YOU'LL CALL
template<class T>
retval func(T param) { return func(ord<9>{},param); } //any "more than 3 value"
This will call the first/second/third/fourth function if condition3 is satisfied, than condition2 than condition1 than none of them.
Other SFINAE triggers
Writing compile-time conditions can be either a matter of explicit specialization or a matter of unevaluated expression success/failure:
for example:
template<class T, class = void>
struct is_vector: std::false_type {};
template<class X>
struct is_vector<vector<X> >:: std::true_type {};
so that is_vector<int>::value is false but is_vecttor<vector<int> >::value is true
Or, by means of introspection, like
template<class T>
struct is_container<class T, class = void>: std::false_type {};
template<class T>
struct is_container<T, decltype(
std::begin(std::declval<T>()),
std::end(std::declval<T>()),
std::size(std::declval<T>()),
void(0))>: std::true_type {};
so that is_container<X>::value will be true if given X x, you can compile std::begin(x) etc.
The trick is that the decltype(...) is actually void (the , operator discards the previous expressions) only if all the sub-expressions are compilable.
There can be even many other alternatives. Hope between all this you can find something useful.
The accepted answer is good for most cases, but fails if two such constructor overloads with different conditions are present. I'm looking for a solution in that case too.
Yes: the accepted solution works but not for two alternative constructor as, by example,
template <int otherN, typename = typename std::enable_if<otherN == 1>::type>
explicit A(A<otherN> const &);
template <int otherN, typename = typename std::enable_if<otherN != 1>::type>
explicit A(A<otherN> const &);
because, as stated in this page,
A common mistake is to declare two function templates that differ only in their default template arguments. This is illegal because default template arguments are not part of function template's signature, and declaring two different function templates with the same signature is illegal.
As proposed in the same page, you can go around this problem applying SFINAE, modifying the signature, to the type of a value (not type) template parameter as follows
template <int otherN, typename std::enable_if<otherN == 1, bool>::type = true>
explicit A(A<otherN> const &);
template <int otherN, typename std::enable_if<otherN != 1, bool>::type = true>
explicit A(A<otherN> const &);
In C++11, you can use a defaulted template parameter:
template <int otherN, class = typename std::enable_if<otherN >= N>::type>
explicit A(A<otherN> const &);
However, if your compiler doesn't support defaulted template parameters yet, or you need multiple overloads, then you can use a defaulted function parameter like this:
template <int otherN>
explicit A(A<otherN> const &, typename std::enable_if<otherN >= N>::type* = 0);
With C++20 you can use the requires keyword
With C++20 you can get rid of SFINAE.
The requires keyword is a simple substitute for enable_if!
Note that the case where otherN == N is a special case, as it falls to the default copy ctor, so if you want to take care of that you have to implement it separately:
template<int N> struct A {
A() {}
// handle the case of otherN == N with copy ctor
explicit A(A<N> const& other) { /* ... */ }
// handle the case of otherN > N, see the requires below
template<int otherN> requires (otherN > N)
explicit A(A<otherN> const& other) { /* ... */ }
// handle the case of otherN < N, can add requires or not
template<int otherN>
explicit A(A<otherN> const& other) { /* ... */ }
};
The requires clause gets a constant expression that evaluates to true or false deciding thus whether to consider this method in the overload resolution, if the requires clause is true the method is preferred over another one that has no requires clause, as it is more specialized.
Code: https://godbolt.org/z/RD6pcE

Perform overload resolution with template meta-programming

Inspired by another question I tried to find a way to deduce the type
of an overload member function given the actual argument used to call
that function. Here is what I have so far:
#include <type_traits>
template<typename F, typename Arg>
struct mem_fun_type {
// perform overload resolution here
typedef decltype(std::declval<F>()(std::declval<Arg>())) result_type;
typedef decltype(static_cast<result_type (F::*)(Arg)>(&F::operator())) type;
};
struct foo {};
struct takes_two
{
void operator()(int);
void operator()(foo);
};
struct take_one {
void operator()(float);
};
int main()
{
static_assert(std::is_same<mem_fun_type<take_one, float>::type,
void (take_one::*)(float)>::value, "Zonk");
static_assert(std::is_same<mem_fun_type<takes_two, double>::type,
void (takes_two::*)(float)>::value, "Zonk");
return 0;
}
As long as the template parameter Arg matches the actual type the
static_cast will succeed, but this is only the most trivial case of
overload resolution (exact match). Is it possible to perform the
complete overload resolution process in template metaprogramming?
This is purely hypothetical and not intended for real-world use.
This is closest I came to it so far: define function returning tables of different sizes and your result is sizeof(select(...)) receiving pointer to function you want to match. To ensure that the code will compile even if function does not exist in given class, you can use separate check has_function.
Result of overload resolution is in select<has_function<T>::value, T>::value.
With this code you can even "resolve" data members, not just functions, it's only a question of making right parameter for select function.
However there is one deficiency here - overload resolution is not on function parameters, but on function type. Meaning none of usual parameter type conversions takes place.
// Verify the name is valid
template <typename T>
struct has_function
{
struct F {int function;};
struct D : T, F {};
template <typename U, U> struct same_;
template <typename C> static char(&select_(same_<int F::*, &C::function>*))[1];
template <typename> static char(&select_(...))[2];
enum {value = sizeof(select_<D>(0)) == 2};
};
// Values to report overload results
enum type { none=1 , function_sz_size_t , function_sz , function_string };
template <bool, typename R> struct select;
template <typename R> struct select<false, R>
{
enum {value = none};
};
template <typename R> struct select<true, R>
{
// Define your overloads here, they don't have to be templates.
template <typename Ret, typename Arg> static char(&select_(Ret (R::*)(const char*, Arg)))[function_sz_size_t];
template <typename Ret, typename Arg> static char(&select_(Ret (R::*)(Arg)))[function_sz];
template <typename Ret> static char(&select_(Ret (R::*)(std::string)))[function_string];
template <typename Ret> static char(&select_(Ret (R::*)(std::string&&)))[function_string];
template <typename Ret> static char(&select_(Ret (R::*)(const std::string&)))[function_string];
static char(&select_(...))[none];
enum {value = sizeof(select_(&R::function))};
};