Can you detect template member of a class using std::is_detected - c++

I use std::experimental::is_detected to determine if class has certain member functions:
#include <utility>
#include <experimental/type_traits>
template<typename USC>
class Descriptor
{
private:
template<class T>
using has_member1_t =
decltype(std::declval<T>().member1(std::declval<std::vector<char> &>()));
public:
static constexpr bool has_member1 =
std::experimental::is_detected_convertible_v<long long,
has_member1_t,
USC>;
};
The problem is I also need to determine if class has certain template member function with following signature:
template<typename Derived>
int member2(Eigen::ArrayBase<Derived> &&)
I've tried to do it like so:
//Inside Descriptor
template<class T, class U>
using has_member2_t =
decltype(std::declval<T>().member2(std::declval<Eigen::ArrayBase<U> &&>()));
static constexpr bool has_member2 =
std::experimental::is_detected_convertible_v<long long,
has_member2_t,
USC>;
but it doesn't work. As I'm not really experienced with C++ TMP I would like to know is there a way to achieve this with std::experimental::is_detected or some other utility?

If c++20 is an option, this kind of code has been made a lot easier to both read and write by using concepts.
#include <iostream>
#include <vector>
struct Foo {
int member1(int) {
return 1;
}
template <typename T>
double member2(std::vector<T>) {
return 2.5;
}
};
struct Bar {};
template <typename T>
concept MyConcept = requires (T t) {
{ t.member1(0) } -> std::same_as<int>; // We can check return type
{ t.template member2<int>(std::vector<int>{}) }; // but we don't have to
};
int main() {
static_assert(MyConcept<Foo>);
static_assert(!MyConcept<Bar>);
}
The issue with your attempt is that you are not passing anything as U for the check. I would also modify it to use the .template member2<...> syntax to explicitly check for a template.
Here is an example of that.
#include <iostream>
#include <vector>
#include <utility>
#include <experimental/type_traits>
struct Foo {
int member1(int) {
return 1;
}
template <typename T>
double member2(std::vector<T>) {
return 2.5;
}
};
struct Bar {};
template<class T, class U>
using has_member2_t =
decltype(std::declval<T>().template member2<U>(std::declval<std::vector<U> &&>()));
int main() {
static constexpr bool has_member2_Foo =
std::experimental::is_detected_convertible_v<long long,
has_member2_t,
Foo, double>;
static constexpr bool has_member2_Bar =
std::experimental::is_detected_convertible_v<long long,
has_member2_t,
Bar, double>;
static_assert(has_member2_Foo);
static_assert(!has_member2_Bar);
}

Related

Templated class - Enable if

I'm trying to do a templated class that runs a function only in certain cases. This is my code:
#include "stdafx.h"
#include <string>
#include <iostream>
template <class T, class U>
struct Typelist
{
typedef T Head;
typedef U Tail;
};
class NullType
{
};
typedef Typelist<int, Typelist<float, Typelist<char*, NullType> > > UsableTypes1;
typedef Typelist<short, Typelist<std::string, NullType> > UsableTypes2;
template <class T>
class MyClass
{
public:
MyClass();
private:
Typelist _types;
};
template<class T>
MyClass<T>::MyClass()
{
_types = T;
}
template<class T>
void MyClass<T>::print(T type)
{
}
MyClass<UsableTypes1> any;
I need to make the code compiler or not only if the variable I pass to the print() function is a type that is in one of the usable types. I know that probably I'll have to use std::enable_if to allow the code to compile or not if print is called with an incorrect type and std::is_same to check the types but I don't know how to combine that functions with a templated class.
This is a test class to help to explain what I want to achieve:
MyClass<UsableTypes1> one;
void TestMyClass()
{
int int_val = 0;
float flt_val = 0.1f;
const char* char_val = "Hi";
short short_val = 10;
std::string str_val = "Hello";
one.print(int_val); // OK
one.print(flt_val); // OK
one.print(char_val); // OK
// one.print( short_val); // compile error
// one.print( str_val ); // compile error
}
Specially I don't know how can I add to print() a non-T-type parameter.
I hope you can help me!
Thank you in advance.
I don't know if you have a good reason for using recursive Typelists to contain your list of types. A more straight forward way would be to make Typelist a variadic template.
Then we can add a constexpr function that returns true if a given type is part of the Typelist.
std::disjunction requires c++17, but something equivalent can be written for c++11 with a recursive template. That will however be more verbose.
#include <iostream>
#include <type_traits>
struct NullType {};
template <typename T, typename U>
struct Typelist {
using Head = T;
using Tail = U;
template <typename Type>
static constexpr bool IsUsable() {
return std::is_same<Type, T>::value;
}
};
template <typename T, typename... U>
struct Typelist<T, Typelist<U...>> {
using Head = T;
using Tail = Typelist<U...>;
template <typename Type>
static constexpr bool IsUsable() {
return std::is_same<Type, T>::value || Typelist<U...>::template IsUsable<Type>();
}
};
using UsableTypes1 = Typelist<int, Typelist<float, Typelist<const char*, NullType>>>;
template <class T>
class MyClass
{
public:
template <typename U>
void print(U u) {
static_assert(T::template IsUsable<U>(), "That is not a usable type");
std::cout << u << std::endl;
}
};
MyClass<UsableTypes1> one;
int main()
{
int int_val = 0;
float flt_val = 0.1f;
const char* char_val = "Hi";
short short_val = 10;
std::string str_val = "Hello";
one.print(int_val); // OK
one.print(flt_val); // OK
one.print(char_val); // OK
// one.print( short_val); // compile error
// one.print( str_val ); // compile error
}

restricting the types using templates in vc++

As far my understanding goes I want to restrict only 2 types int and string for the following class, just like in java template definition with extends.
template<typename T>
typename std::enable_if<std::is_same<T,int>::value || std::is_same<T,string>::value>::type
class ExchangeSort
{
public:
void bubbleSort(T buffer[], int s);
void print(T buffer[], int s);
void bubbleSort(const vector<T>& vec);
};
But if I'm instantiating like below
ExchangeSort<int>* sortArray = new ExchangeSort<int>;
I'm getting errors for the above line ExchangeSort is undefined. What is the problem ?
SFINAE can be used to conditionally disable function overloads or template specialisations. It makes no sense to try to use it to disable a class template, since class templates cannot be overloaded. You'll be better off using a static assertion:
template<typename T>
class ExchangeSort
{
static_assert(std::is_same<T,int>::value || std::is_same<T,string>::value, "ExchangeSort requires int or string");
public:
// The rest as before
As to the errors you were getting, the code didn't make syntactic sense. enable_if can only appear where a type is expected. With functions, it's often used to wrap the return type, in which case it's syntactically similar to what you wrote. But with classes, there's no type between template and the class definition.
Here's another way which allows the possibility of adding further specialisations down the line:
#include <type_traits>
#include <vector>
#include <string>
//
// Step 1 : polyfill missing c++17 concepts
//
namespace notstd {
template<class...> struct disjunction : std::false_type { };
template<class B1> struct disjunction<B1> : B1 { };
template<class B1, class... Bn>
struct disjunction<B1, Bn...>
: std::conditional_t<bool(B1::value), B1, disjunction<Bn...>> { };
}
//
// Step 2 : create a test to see if a type is in a list
//
namespace detail {
template<class T, class...Us>
struct is_one_of : notstd::disjunction< std::is_same<T, Us>... > {};
}
template<class T, class...Us>
static constexpr auto IsOneOf = detail::is_one_of<T, Us...>::value;
//
// Step 3 : declare the default specialisation, but don't define it
//
template<class T, typename Enable = void>
struct ExchangeSort;
//
// Step 4 : define the specialisations we want
//
template<typename T>
class ExchangeSort<T, std::enable_if_t<IsOneOf<T, int, std::string>>>
{
public:
void bubbleSort(T buffer[], int s);
void print(T buffer[], int s);
void bubbleSort(const std::vector<T>& vec);
};
//
// Test
//
int main()
{
auto esi = ExchangeSort<int>();
auto ess = ExchangeSort<std::string>();
// won't compile
// auto esd = ExchangeSort<double>();
}

How to support multiple construction signatures in a factory design?

I'm working with the following (simplified) factory design to create objects of some inheritance hierarchy, shouldn't be anything special:
// class to create
class Class
{
public:
Class(Type type, Foo foo);
};
// Simple creator class.
// Used in practice to do some runtime checks about whether or not construction is allowed.
class Creator
{
public:
Class* create( Type type, Foo foo ) const
{
return new Class( type, foo );
}
};
class Factory
{
public:
Factory
{
// fill object creator map on construction
_map[ "name" ] = new Creator<Class>;
}
Class* create( const std::string& name, Type type, Foo foo )
{
// fowards to map entry
return _map[name]->create( type, foo );
}
private:
std::map<std::string, Creator*> _map;
}
// client code
int main()
{
Factory f;
factory.create(name, type, foo);
}
Now I run into problems once I want to create subclasses which have a different constructor signature because the factory imposes a fixed signature on the entire inheritance hierarchy. I.e. for the following class I have no way of specifying the new 3rd parameter via the factory construction without imposing this extended signature on all other class of my hierarchy again.
class ExtClass : public Class
{
public:
Class(Type type, Foo foo, NewMember nm)
: Class(type, foo),
_nm(nm)
private:
NewMember _nm;
};
Is there a way to make this work with my current design without making pricinpal changes? I'm thinking of using templates or bind objects to make varying argument calls possible.
Or would you in this case suggest a different solution than the factory design?
This answer is different enough to my first solution and it includes what you might consider "principal changes" that I have made it a separate answer:
In my opinion, it is superior to my earlier solution, but it depends what your exact requirements are. The features here are:
Creator id is unique.
CreateObject supports implicit conversion of parameters.
The same limitation that the constructors must take const& parameters exists. It might not matter, but this solution only requires C++11. It would, of course, be a bit simpler with the new C++17 tuple features.
#include <boost/functional/factory.hpp>
#include <boost/function.hpp>
#include <boost/variant.hpp>
#include <map>
#include <stdexcept>
#include <tuple>
#include <type_traits>
#include <utility>
// Just for debugging.
#include <iostream>
#include <typeinfo>
#include <cxxabi.h>
// Tuple manipulation.
template <typename Signature>
struct signature_impl;
template <typename ReturnType, typename... Args>
struct signature_impl<ReturnType(Args...)>
{
using return_type = ReturnType;
using param_types = std::tuple<Args...>;
};
template <typename T>
using signature_t = signature_impl<T>;
template <std::size_t... Ints>
struct indices {};
template <std::size_t N, std::size_t... Ints>
struct build_indices : build_indices<N-1, N-1, Ints...> {};
template <std::size_t... Ints>
struct build_indices<0, Ints...> : indices<Ints...> {};
template <typename Tuple>
using make_tuple_indices = build_indices<std::tuple_size<typename std::remove_reference<Tuple>::type>::value>;
// The multiple-signature factory.
template <class AbstractProduct, typename IdentifierType, typename... ProductCreators>
class multifactory
{
using functions = boost::variant<boost::function<ProductCreators>...>;
std::map<IdentifierType, functions> associations_;
template <typename Signature>
struct dispatch_foo
{
template <typename CreateArgs, std::size_t... Indices>
typename std::enable_if<std::is_convertible<CreateArgs, typename signature_t<Signature>::param_types>::value, AbstractProduct>::type
static apply(boost::function<Signature> const &f, CreateArgs && t, indices<Indices...>)
{
return f(std::get<Indices>(std::forward<CreateArgs>(t))...);
}
template <typename CreateArgs, std::size_t... Indices>
typename std::enable_if<!std::is_convertible<CreateArgs, typename signature_t<Signature>::param_types>::value, AbstractProduct>::type
static apply(boost::function<Signature> const &, CreateArgs &&, indices<Indices...>)
{
return nullptr;
}
};
template <typename... CreateArguments>
struct dispatcher : boost::static_visitor<AbstractProduct>
{
std::tuple<CreateArguments...> args;
dispatcher(CreateArguments const&... args) : args{std::forward_as_tuple(args...)} {}
template <typename Signature>
AbstractProduct operator()(boost::function<Signature> const &f) const
{
int status;
std::cout << "visitor: " << abi::__cxa_demangle(typeid(Signature).name(), nullptr, 0, &status) << "\n";
return dispatch_foo<Signature>::apply(f, args, make_tuple_indices<std::tuple<CreateArguments...>>{});
}
};
public:
template <typename ProductCreator>
bool Register(IdentifierType id, ProductCreator &&creator) {
return associations_.emplace(id, std::forward<ProductCreator>(creator)).second;
}
bool Unregister(const IdentifierType& id) {
return associations_.erase(id) == 1;
}
template <typename... Arguments>
AbstractProduct CreateObject(const IdentifierType& id, Arguments const& ... args) {
auto i = associations_.find(id);
if (i != associations_.end()) {
dispatcher<Arguments...> impl(args...);
return boost::apply_visitor(impl, i->second);
}
throw std::runtime_error("Creator not found.");
}
};
struct Arity {
virtual ~Arity() = default;
};
struct Nullary : Arity {};
struct Unary : Arity {
Unary() {} // Also has nullary ctor.
Unary(int) {}
};
int main(void)
{
multifactory<Arity*, int, Arity*(), Arity*(const int&)> factory;
factory.Register(0, boost::function<Arity*()>( boost::factory<Nullary*>() ));
factory.Register(1, boost::function<Arity*(const int&)>(boost::factory<Unary*>()) );
auto a = factory.CreateObject(0);
assert(a);
assert(typeid(*a) == typeid(Nullary));
auto b = factory.CreateObject(1, 2);
assert(b);
assert(typeid(*b) == typeid(Unary));
}
Apologies for the different naming conventions, but this is the C++14 solution that I currently use. The two main shortcomings are
when calling CreateObject, the type of the value passed as an
argument must be the same as the type registered. You can't pass in
a float and call a constructor registered with a double
signature.
Due to an implementation detail in boost::bind,
parameters must be const &.
A design limitation because I wanted to use boost::factory is that objects of that class must be wrapped in a boost::function (to disambiguate the function signature).
So it works but it could definitely be improved with more metaprogramming wisdom:
#include <boost/functional/factory.hpp>
#include <boost/function.hpp>
#include <boost/bind.hpp>
#include <cassert>
#include <map>
#include <tuple>
#include <type_traits>
#include <utility>
template <class AbstractProduct, typename IdentifierType, typename... ProductCreators>
class Factory
{
using AssociativeContainers = std::tuple<std::map<IdentifierType, boost::function<ProductCreators>>...>;
public:
template <typename Product, typename... Arguments>
bool Register(const IdentifierType& id, boost::function<Product(Arguments...)> creator) {
auto &foo = std::get<std::map<IdentifierType, boost::function<AbstractProduct(const Arguments&...)>>>(associations_);
return foo.emplace(id, creator).second;
}
// This function left as an exercise to the reader...
bool Unregister(const IdentifierType& id) {
return associations_.erase(id) == 1;
}
template <typename... Arguments>
AbstractProduct CreateObject(const IdentifierType& id, Arguments&& ... args) const {
auto const &foo = std::get<std::map<IdentifierType, boost::function<AbstractProduct(const Arguments&...)>>>(associations_);
auto const i = foo.find(id);
if (i != foo.end()) {
return (i->second)(std::forward<Arguments...>(args)...);
}
throw std::runtime_error("Creator not found.");
}
private:
AssociativeContainers associations_;
};
struct Arity {
virtual ~Arity() = default;
};
struct Nullary : Arity {};
struct Unary : Arity {
Unary() {}
Unary(double x) : x(x) {}
double x;
};
int main(void)
{
Factory<Arity*, int, Arity*(), Arity*(const double&)> factory;
factory.Register(0, boost::function<Arity*()>{boost::factory<Nullary*>()} );
factory.Register(1, boost::function<Arity*(const double&)>{boost::bind(boost::factory<Unary*>(), _1)});
auto x = factory.CreateObject(1, 2.0);
assert(typeid(*x) == typeid(Unary));
x = factory.CreateObject(0);
assert(typeid(*x) == typeid(Nullary));
}

Partial specializations of templatized alias declarations

In this question I am led to a particular solution which involves partial specializations of templatized alias declarations. The generic case is described in this answer. Suppose I have a template class
template<typename T, ...>
class X {
// ....
};
Rather than leaving T free and specializing the other template parameters I am in a situation in which the other arguments depend on T, and on T alone. As a very concrete example (more manageable than the example in the other question) consider a template class
template<typename T, T absVal(T)>
class Number_impl {
private:
T _t;
public:
Number_impl(T t): _t(t) {}
T abs() const {return absVal(_t);}
};
Possible specializations are
Number_impl<int, std::abs>;
and
Number_impl<double, std::fabs>;
(I know there are overloaded abs versions, this is just for the sake of illustration. See my other example if you want).
Ideally I would like to define a template class Number depending on a single argument, the type, so that Number<int> is equal to
Number_impl<int, std::abs>;
and Number<double> is equal to
Number_impl<double, std::fabs>;
Something like the following (which doesn't work):
template<typename T>
using Number = Number_impl<T, nullptr>;
template<>
using Number<int> = Number_impl<int, std::abs>;
template<>
using Number<double> = Number_impl<double, std::fabs>;
Does anyone know if and how this can be made to work, or how the same can be achieved in a different way?
The normal way to do this kind of thing is the same way the standard library does it - with a traits class that you can specialise:
#include <iostream>
#include <cmath>
template<typename T> struct NumberTraits;
template<typename T, class Traits = NumberTraits<T>>
class Number {
private:
T _t;
public:
Number(T t): _t(t) {}
T abs() const {
return Traits::abs(_t);
}
};
template<> struct NumberTraits<int>
{
static int abs(int i) {
return std::abs(i);
}
};
template<> struct NumberTraits<double>
{
static double abs(double i) {
return std::fabs(i);
}
};
using namespace std;
auto main() -> int
{
Number<int> a(-6);
Number<double> b(-8.4);
cout << a.abs() << ", " << b.abs() << endl;
return 0;
}
expected output:
6, 8.4
You may add a layer:
template<typename T, T absVal(T)>
class Number_impl {
private:
T _t;
public:
Number_impl(T t): _t(t) {}
T abs() const {return absVal(_t);}
};
template<typename T> struct Number_helper;
template<> struct Number_helper<int> { using type = Number_impl<int, std::abs>; };
template<> struct Number_helper<double> { using type = Number_impl<double, std::fabs>; };
template<typename T>
using Number = typename Number_helper<T>::type;

Invalid use of incomplete type with templates and decltype

I need to make the following work.
This is a reduced version of my actual code, but basically the difficulty is the same, i.e., to deduce the return type of a factory method.
Specifically, I need either the second or third variant of DeduceObjectT (both commented), instead of the first, which requires the FactoryT::ObjectT typedef.
#include <string>
#include <utility>
#include <memory>
template<class FactoryT>
using DeduceObjectT = typename FactoryT::ObjectT;
//template<class FactoryT>
//using DeduceObjectT = typename decltype(std::declval<FactoryT>().create())::element_type;
//template<class FactoryT>
//using DeduceObjectT = typename std::result_of<decltype(&FactoryT::create)(FactoryT)>::type::element_type;
template<class FactoryT>
struct FactoryUser
{
typedef DeduceObjectT<FactoryT> ObjectT;
};
template<class FactoryUserT>
struct Foo
{
typedef typename FactoryUserT::ObjectT ObjectT;
};
struct StringFactory
{
typedef std::string ObjectT; // want to omit this
std::unique_ptr<std::string> create()
{
return nullptr;
}
Foo<FactoryUser<StringFactory>> t;
};
int main()
{
StringFactory f;
return 0;
}
After numerous tries I still get 'error: invalid use of incomplete type ‘struct StringFactory’'.
I also tried deducing the type by means of a default template argument of FactoryUser.
I really don't understand, why am I getting the error considering that the point that triggers instantiation of all templates is at the end -- the line that declares the data member t.
Compiler is gcc 4.7.3. with -std=c++0x -O0
Try something like this instead:
template <typename Factory>
struct ProductTypedef
{
typedef typename decltype(std::declval<Factory>().create())::element_type ObjectT;
};
struct StringFactory : public ProductTypedef<StringFactory> // CRTP
{
std::unique_ptr<std::string> create()
{
return nullptr;
}
};
You can alter Foo a little bit for your code to work:
#include <string>
#include <utility>
#include <memory>
template<class FactoryT>
using DeduceObjectT = typename FactoryT::ObjectT;
template<class FactoryT>
struct FactoryUser
{
typedef DeduceObjectT<FactoryT> ObjectT;
};
// Provide a way for ObjectType to be specified at the time
// the template is instantiated.
template<class FactoryUserT, typename ObjectType = typename FactoryUserT::ObjectT>
struct Foo
{
typedef ObjectType ObjectT;
};
struct StringFactory
{
std::unique_ptr<std::string> create()
{
return nullptr;
}
Foo<FactoryUser<StringFactory>, std::string> t;
};
int main()
{
StringFactory f;
return 0;
}