I was wondering if it is possible to use SFINAE to set an alias template in a different class depending on the existence or not of an alias in a traits class.
template<class T>
struct Foo_Traits;
struct Foo1;
template<>
struct Foo_Traits<Foo1>
{
using type1 = Bar1;
using type2 = Bar2;
};
struct Foo2;
template<>
struct Foo_Traits <Foo2>
{
using type1 = Bar3;
};
Essentially we have 2 classes Foo1 and Foo2 and their traits class that define type aliases in this case to simplify it.
In all cases we will have type1 alias and in some cases we will have a type2.
In a different class (in my cases it is actually the base class of Foo) I want to set aliases for these types.
template<typename ImplT>
class FooBase
{
using T1 = typename Foo_Traits<ImplT>::type1;
using T2 = typename std::conditional< defined<typename Foo_Traits<ImplT>::type1>::value ,
typename Foo_Traits<ImplT>::type2,
T1>::type;
};
How can I actually achieve something of the sort that is written in pseudocode over at
using T2 = etc...
Your answer can be found in N3911 that proposes void_t.
Given:
template <typename...>
using void_t = void;
You can write your has_type2_member predicate like so:
template <typename, typename = void>
struct has_type2_member : std::false_type {};
template <typename T>
struct has_type2_member<T, void_t<typename T::type2>> : std::true_type {};
We can't use this predicate directly, but we can modify it to our needs.
template <typename ImplT>
class FooBase
{
using T1 = typename Foo_Traits<ImplT>::type1;
template <typename, typename = void>
struct type2_or_type1 {
using type = T1;
};
template <typename T>
struct type2_or_type1<T, void_t<typename T::type2>> {
using type = typename T::type2;
};
using T2 = typename type2_or_type1<Foo_Traits<ImplT>>::type;
};
Related
I would like to check if there exist a member function with signature fit to a parameter pack. I began with the known SFINAE concept, while trying to extend it for considering also a parameters pack. But at this point I found that I don't know how to do it.
I try to do something like this:
// Note: T object may have several functions with the name foo, but with different signatures.
// a function foo also can be a template one with variadic parameters pack.
template<typename T, typename...Args>
class HAS_FUNCTION_FOO
{
template<typename U>
static bool test(decltype(&U::foo));
template<typename U>
static float test(...);
public:
static constexpr bool value = std::is_integral<decltype(test<T>(Args...))>::value;
//-------------------------------------------------------------^^^^^^^^^
// how to do it?
};
I would like to use it for declaring specific object at compile time - something like this:
class Bar
{
public:
template<typename T, typename...Args>
void doSomthing(T* p, Args&&...parameters)
{
// get correct object type:
// if T has a function called foo with parameters fits for pack, then declare A, o.w declare B.
using ObjType = typename std::conditional<HAS_FUNCTION_FOO<T, Args>::value, A, B>::type;
// compute
ObjType::doSomthing(p, std::forward<Args>(parameters)...);
}
private:
struct A
{
template<typename T, typename...Args>
static void doSomthing(T* p, Args&&...parameters)
{
p->foo(std::forward<Args>(parameters)...);
}
};
struct B
{
template<typename T, typename...Args>
static void doSomthing(T* p, Args&&...parameters)
{
// do something else
}
};
};
Something like this, perhaps:
template<typename T, typename...Args>
class HAS_FUNCTION_FOO
{
template <typename U>
static std::true_type test(
typename std::enable_if<sizeof(
decltype(std::declval<U>().foo(std::declval<Args>()...))*) != 0>::type*
);
template <typename U>
static std::false_type test(...);
public:
static constexpr bool value = decltype(test<T>(nullptr))::value;
};
Demo
I am trying to write a specialized decay with template specialization on certain types:
template <typename T>
struct stateful_decay {
using type = T;
};
template <typename T>
struct stateful_decay<T&&> {
using type = T;
};
template <>
struct stateful_decay<PullTask&&> {
using type = PullTask;
};
template <>
struct stateful_decay<PullTask&> {
using type = PullTask;
};
template <>
struct stateful_decay<PullTask> {
using type = PullTask;
};
template <>
struct stateful_decay<const PullTask&&> {
using type = PullTask;
};
template <>
struct stateful_decay<const PullTask&> {
using type = PullTask;
};
template <>
struct stateful_decay<const PullTask> {
using type = PullTask;
};
template <typename T>
using stateful_decay_t = typename stateful_decay<T>::type;
Apparently, PullTask specialization has a lot of verbosity. Basically, any thing related to PullTask type should decay to PullTask. Is there any way to improve this? I am thinking about to use std::decay_t but didn't know how to do so.
#include <type_traits>
template <typename T>
struct stateful_decay
: std::conditional<std::is_same<PullTask, std::decay_t<T>>{}, PullTask, T> {};
template <typename T>
struct stateful_decay<T&&>
: stateful_decay<T> {};
template <typename T>
using stateful_decay_t = typename stateful_decay<T>::type;
DEMO
I have a type
typedef std::pair<ConstIterator, ConstIterator> Range;
with
typedef typename std::vector<T>::const_iterator ConstIterator;
I would now like to use std::iterator_traits to deduce the type the iterators of a Range are pointing to.
Could anybody please tell me how I can achieve this, from an object of type Range?
You can write a type trait, partially specialized on a pair:
template <typename T>
struct value_type {
using type = typename std::iterator_traits<T>::value_type;
};
template <typename T>
struct value_type<std::pair<T, T>>
: value_type<T>
{ };
This will support both your pair based ranges, and most iterables:
template<class R>
struct value_type {
using iterator_type = decltype( std::begin(std::declval<R>()) );
using type=typename std::iterator_traits<iterator_type>::value_type;
};
template<class It>
struct value_type<std::pair<It,It>> {
using type=typename std::iterator_traits<It>::value_type;
};
template<class X>
using value_t = typename value_type<X>::type;
note that the value type of a const iterator is a non-const value.
The above is not SFINAE friendly -- an industrial quality one would be.
You're explicitly allowed to add template specializations to the std namespace for user-defined types (thanks Barry for the precision !). If you rework your Range to be an actual type (not just a typedef), you can do this :
struct Range : std::pair<ConstIterator, ConstIterator> {
using std::pair<ConstIterator, ConstIterator>::pair;
};
namespace std {
template <>
struct iterator_traits<Range> : iterator_traits<ConstIterator> {};
}
When you buff your Range a bit, I expect this to evolve into :
namespace std {
template <class T>
struct iterator_traits<Range<T>> : iterator_traits<T> {};
}
I want to use a type that was defined inside a template class. How can I do it?
template < typename A, typename B>
struct internal {
const static std::string value;
typedef B type;
};
template < typename A > using external = struct internal<A, int>;
external::type object;
I would like to know how to write a type_traits class to detect whether two types are specializations of the same template class. The big problem is that it should work for mixed types/non-types template class like:
template <typename T, std::size_t N>
class MyClass {};
Is it possible to design a such thing?
I don't think you can do this in general for an arbitrary class template with a mix of type and non-type parameters.
You can get close for more specific sets of parameters, but I don't know any way to handle the general case:
#include <type_traits>
template <typename T, std::size_t N>
class MyClass {};
// assume not the same
template<typename T, typename U>
struct my_trait : std::false_type
{ };
// both specializations of MyClass
template<typename T1, std::size_t N1, typename T2, std::size_t N2>
struct my_trait<MyClass<T1, N1>, MyClass<T2, N2>>
: std::true_type
{ };
// both specializations of some class template Templ<typename, std::size_t>
template<template<typename, std::size_t> class Templ, typename A1, std::size_t S1, typename A2, std::size_t S2>
struct my_trait<Templ<A1, S1>, Templ<A2, S2>>
: std::true_type
{ };
// both specializations of some class template Templ<typename...>
template<template<typename...> class Templ, typename... A1, typename... A2>
struct my_trait<Templ<A1...>, Templ<A2...>>
: std::true_type
{ };