Hide class template instance based on traits - c++

I have a traits class like the following that reflects the compatibility between two types:
template <typename ObjectType, typename ArgumentType>
struct Traits
{
static const bool SpecialMethodAvailable = false;
};
The single member determines if SpecialMethod() can be called on objects of type ObjectType with argument of type ArgumentType.
A simple class that supports this is the following:
class ClassWithSpecialMethod
{
public:
template <typename T>
void SpecialMethod(T param) { std::cout << "Special Method called with " << param << std::endl; }
};
template <typename ArgumentType>
struct Traits<ClassWithSpecialMethod, ArgumentType>
{
static const bool SpecialMethodAvailable = true;
};
I want to write a worker class that uses this traits class and calls the special method if it is available. Basically something like the following:
template <typename T>
struct Worker
{
static void DoSomething(T t, GlobalDataType& globalData)
{
//if Traits<GlobalDataType, T>::SpecialMethodAvailable
// call the method
//else
// do something different
}
};
I tried to realize this using std::enable_if. My solution works with the Visual C 14.1 compiler but not with GCC. Here is what I tried:
template <typename T, typename Enable = void>
struct Worker
{
static void DoSomething(T t, GlobalDataType& globalData)
{
std::cout << "There is no special method (called with " << t << ")" << std::endl;
}
};
template <typename T>
struct Worker<T, typename std::enable_if<Traits<GlobalDataType, T>::SpecialMethodAvailable>::type>
{
static void DoSomething(T t, GlobalDataType& globalData)
{
globalData.SpecialMethod(t);
}
};
I used this as follows:
typedef ... GlobalDataType; //before the template declarations
int main()
{
GlobalDataType td;
int integer = 0;
Worker<int>::DoSomething(integer, td);
}
If GlobalDataType is typedef'ed to ClassWithSpecialMethod, both VS and GCC compile fine and output correctly:
Special Method called with 0
However, if GlobalDataType is typedef'ed to something that does not allow the special method (e.g. int), VS still produces the correct output while GCC results in a compile error:
In static member function ‘static void Worker::SpecialMethodAvailable>::type>::DoSomething(T, GlobalDataType&)’:
source.cpp:38:15: error: request for member ‘SpecialMethod’ in ‘globalData’, which is of non-class type
GlobalDataType {aka int}’
Can someone explain why this does not work as intended under GCC? What would be alternatives?
Link to online compiler

As explained by Jarod42, this method
static void DoSomething(T t, GlobalDataType& globalData)
{
globalData.SpecialMethod(t);
}
with GlobalDataType fixed as int, is ever wrong (for ever T type) because it's sure that int is without SpecialMethod().
To solve this problem with a minimum code change, you can templatize the second parameter
template <typename U>
static void DoSomething(T t, U & globalData)
{ globalData.SpecialMethod(t); }
If you want that DoSomething() receive (as second parameter) only a GlobalDataType, you can impose it enabling DoSomething using SFINAE, only if U is GlobalDataType. Something as
template <typename U>
static typename std::enable_if<std::is_same<U, GlobalDataType>{}>
DoSomething(T t, U & globalData)
{ globalData.SpecialMethod(t); }
What would be alternatives?
I propose you a completely different way, based (following the std::declval() example) over declaration of functions.
First of all, a couple of template helper functions
template <typename ObjectType, typename ... Args>
constexpr auto withSpecialMethodHelper (int)
-> decltype(std::declval<ObjectType>.SpecialMethod(std::declval<Args>...),
std::true_type{} );
template <typename ... Args>
constexpr std::false_type withSpecialMethodHelper (long);
Now you can write the declaration of a template function that return std::true_type if ObjectType has a SpecialMethod() that can be called with a variadic list of arguments of type Args...
template <typename ObjectType, typename ... Args>
constexpr auto withSpecialMethod ()
-> decltype( withSpecialMethodHelper<ObjectType, Args...>(0) );
or maybe better, as suggested by Jarod42, through using
template <typename ObjectType, typename ... Args>
using withSpecialMethod
= decltype( withSpecialMethodHelper<ObjectType, Args...>(0) );
If you can use C++14, you can also define a withSpecialMethod_v template constexpr variable
template <typename ObjectType, typename ... Args>
constexpr bool withSpecialMethod_v
= decltype(withSpecialMethod<ObjectType, Args...>())::value;
in case of declared function or
template <typename ObjectType, typename ... Args>
constexpr bool withSpecialMethod_v
= withSpecialMethod<ObjectType, Args...>::value;
in case of using, that can simplify the use.
Now the Worker class and specialization become
template <typename T, bool = withSpecialMethod_v<GlobalDataType, T>>
struct Worker
{
static void DoSomething (T t, GlobalDataType & globalData)
{
std::cout << "There is no special method (called with " << t << ")"
<< std::endl;
}
};
template <typename T>
struct Worker<T, true>
{
template <typename U>
static void DoSomething(T t, U & globalData)
{ globalData.SpecialMethod(t); }
};

Mvsc 14 doesn't do the 2 phases look-up needed for template.
gcc does (and is correct).
globalData.SpecialMethod(t); is incorrect for any t immediatly so the error. (globalData.SpecialMethod is incorrect and doesn't depend of template parameter).
By post-pone the evaluation you might have what you want:
template <typename T>
struct Worker<T, std::enable_if_t<Traits<GlobalDataType, T>::SpecialMethodAvailable>>
{
template <typename G, typename U>
static void f(G& g, U& u)
{
g.SpecialMethod(u);
}
static void DoSomething(T t, GlobalDataType& globalData)
{
f(globalData, t);
}
};
Demo

Related

How to detect if a function exists?

I'm trying to detect if a specific overload for my function is callable. I assumed I could do something similar to this answer, but I believe the issue is that the function signature template<typename From, typename To> convert(const From&) is well defined, but the instantiation is not.
#include <iostream>
#include <string>
template<typename From, typename To>
To convert(const From& from)
{
// I have a lot of additional template specializations for this function
return from;
}
template<typename From, typename To>
struct IsConvertible
{
template<typename = decltype(convert<From, To>(From()))>
static std::true_type test(int);
template<typename T>
static std::false_type test(...);
static bool const value = decltype(test(0))::value;
};
int main()
{
std::cout << "IsConvertible=" << IsConvertible<int, float>::value << std::endl;
// Returns 1 as expected
std::cout << "IsConvertible=" << IsConvertible<int, std::string>::value << std::endl;
// Returns 1, expected 0. The issue seems to be that decltype(convert<From, To>(From()))
// is somehow ok, although convert<int, std::string>(1) definitly isn't
}
I want to use IsConvertible for some additional metaprogramming. Is it possible to detect if the template<typename From, typename To> To convert(const From&) function is actually callable?`
With declaration of
template<typename From, typename To> To convert(const From& from);
Your traits
template<typename From, typename To>
struct IsConvertible
would always detect presence of convert function.
One way to fix it is overloads and/or SFINAE:
template <typename> struct Tag{};
int convertImpl(tag<int>, const std::string& from);
float convertImpl(tag<float>, const std::string& from);
// overloads ...
template<typename From, typename To>
auto convert(const From& from)
-> decltype(convertImpl(tag<To>{}, from))
{
return convertImpl(tag<To>{}, from);
}
I might have misunderstood your question but is not the using std::is_invocable enough in this case as showcased in the following?
#include<type_traits>
template<typename From, typename To>
To convert(const From& from)
{
// I have a lot of additional template specializations for this function
return from;
}
template<>
std::string convert(const int& from)
{
//silly specialization
return "2"+from;
}
struct Foo{
int bar;
};
int main()
{
//ok specialization is called
std::cout<<std::is_invocable<decltype(convert<int,std::string>),std::string>::value<<std::endl;
//no way I can convert int to Foo, specialization required
std::cout<<std::is_invocable<decltype(convert<int,Foo>),Foo>::value<<std::endl;
return 0;
}
I see some problems in your code.
Without a particular order...
(1) SFINAE, using decltype(), check only the presence of a declared function; doesn't check if that function is defined or if it's definition works (compile) or not.
I propose you to rewrite convert() using directly SFINAE to declare it only when is compilable
template <typename To, typename From,
decltype( To(std::declval<From>()), bool{} ) = true>
To convert (From const & f)
{ return f; }
This way convert() is declared only if you can construct a To object starting from a From object.
(2) Observe that I've also switched the order of To and From: this way you can call the convert() function explicating only the To type
convert<float>(0); // From is deduced as int from the 0 value
If you declare To (that isn't deducible) after From (that is deducible), you necessarily have to explicit both types, calling the function, also when the From type is deducible.
(3) Your IsConvertible struct doesn't works.
It's a common error using SFINAE.
When you write
template<typename = decltype(convert<From, To>(From()))>
static std::true_type test(int);
you're trying enable/disable this test() method using SFINAE over From and To that are the template parameters of the struct
Wrong.
SFINAE works over template parameters of the method itself.
If you want to use SFINAE, you have to transform From and To in template parameters of the method; by example
template <typename F = From, typename T = To,
typename = decltype(convert<F, T>(std::declval<F>()))>
static std::true_type test(int);
Now SFINAE uses F and T that are template parameters of the test() method and this is correct.
(4) Observe that I've written std::declval<F>() instead of F(). It's because you're not sure that F (From) is default constructible. With std::declval() you go around this problem.
I propose a different IsConvertible custom type traits that take in count the From/To inversion and demand to the value call of test() the From+To->F+T type conversion
template <typename To, typename From>
struct IsConvertible
{
template <typename T, typename F,
typename = decltype(convert<T>(std::declval<F>()))>
static std::true_type test(int);
template <typename...>
static std::false_type test(...);
static bool const value = decltype(test<To, From>(0))::value;
};
(5) you're expecting that
IsConvertible<int, std::string>::value
is zero; but you forgetting that std::string is constructible from int; so this value (or IsConvertible<std::string, int>, switching To and From) should be one.
The following is a corrected full working example
#include <iostream>
#include <string>
#include <vector>
template <typename To, typename From,
decltype( To(std::declval<From>()), bool{} ) = true>
To convert (From const & f)
{ return f; }
template <typename To, typename From>
struct IsConvertible
{
template <typename T, typename F,
typename = decltype(convert<T>(std::declval<F>()))>
static std::true_type test(int);
template <typename...>
static std::false_type test(...);
static bool const value = decltype(test<To, From>(0))::value;
};
int main ()
{
std::cout << "IsConvertible=" << IsConvertible<float, int>::value
<< std::endl;
std::cout << "IsConvertible=" << IsConvertible<int, std::string>::value
<< std::endl;
}

Check if a function template is unary

I am trying to check if a function argument passed is unary or not, something like so
template <typename Func>
using EnableIfUnary = std::enable_if_t<std::is_same<
decltype(std::declval<Func>()(std::declval<const int&>())),
decltype(std::declval<Func>()(std::declval<const int&>()))>::value>;
template <typename Func, EnableIfUnary<Func>* = nullptr>
void do_something(Func func) { ... }
// and use like so
template <typename Type>
void foo(Type) { cout << "foo(Type)" << endl; }
template <typename Type>
void bar(Type) { typename Type::something{}; }
int main() {
do_something(foo);
return 0;
}
Is there a better way to check if a function is unary? My current approach doesn't work when the function pass in (foo() in my example) uses the type in a way that would not work with ints.
In the above case foo is legal and bar isn't, since there is no type named something in int (which is what the enable if checks for)
template<typename...>
struct is_unary_function : std::false_type {};
template<typename T, typename R>
struct is_unary_function<R(*)(T)> : std::true_type {};
Live Demo

Function template taking a template non-type template parameter

How does one take a templated pointer to a member function?
By templated I mean that the following types are not known in advance:
template param T is class of the pointer to member
template param R is the return type
variadic template param Args... are the parameters
Non-working code to illustrate the issue:
template <???>
void pmf_tparam() {}
// this works, but it's a function parameter, not a template parameter
template <class T, typename R, typename... Args>
void pmf_param(R (T::*pmf)(Args...)) {}
struct A {
void f(int) {}
};
int main() {
pmf_tparam<&A::f>(); // What I'm looking for
pmf_param(&A::f); // This works but that's not what I'm looking for
return 0;
}
Is it possible to achieve the desired behavior in C++11?
I don't think this notation is possible, yet. There is proposal P0127R1 to make this notation possible. The template would be declared something like this:
template <auto P> void pmf_tparam();
// ...
pmf_tparam<&S::member>();
pmf_tparam<&f>();
The proposal to add auto for non-type type parameters was voted into the C++ working paper in Oulu and the result was voted to become the CD leading towards C++17 also in Oulu. Without the auto type for the non-type parameter, you'd need to provide the type of the pointer:
template <typename T, T P> void pmf_tparam();
// ...
pmf_tparam<decltype(&S::member), &S::member>();
pmf_tparam<decltype(&f), &f>();
As you've not said really what you are after in the function, the simplest is:
struct A {
void bar() {
}
};
template <typename T>
void foo() {
// Here T is void (A::*)()
}
int main(void) {
foo<decltype(&A::bar)>();
}
However if you want the signature broken down, I'm not sure there is a way to resolve the types directly, however you can with a little indirection...
struct A {
void bar() {
std::cout << "Call A" << std::endl;
}
};
template <typename R, typename C, typename... Args>
struct composer {
using return_type = R;
using class_type = C;
using args_seq = std::tuple<Args...>;
using pf = R (C::*)(Args...);
};
template <typename C, typename C::pf M>
struct foo {
static_assert(std::is_same<C, composer<void, A>>::value, "not fp");
typename C::return_type call(typename C::class_type& inst) {
return (inst.*M)();
}
template <typename... Args>
typename C::return_type call(typename C::class_type& inst, Args&&... args) {
return (inst.*M)(std::forward<Args...>(args...));
}
};
template <class T, typename R, typename... Args>
constexpr auto compute(R (T::*pmf)(Args...)) {
return composer<R, T, Args...>{};
}
int main() {
foo<decltype(compute(&A::bar)), &A::bar> f;
A a;
f.call(a);
}
The above should do what you are after...
What you can do is
template <template T, T value>
void pmf_tparam() {}
and then
pmf_tparam<decltype(&A::f), &A::f>();
The problem is not knowing the type of the argument and wanting a template argument of that type.
With an additional decltype (still in the templated parameter), this works:
#include <iostream>
using namespace std;
template <typename T, T ptr>
void foo (){
ptr();
}
void noop() {
cout << "Hello" << endl;
}
int main() {
//Here have to use decltype first
foo<decltype(&noop), noop>();
return 0;
}

Is it possible to place function pointer in template parameter ahead of dependent type?

I have a template that has a function pointer as it's 2nd parameter and a type that the function pointer is dependent on as it's first.
i.e.
template <typename P, typename void(*fn)(P)>
auto function(P) -> otherType<P, fn>;
I want to make it so that I can just specify the function pointer in the template list without having to specify the dependent type as that type should somehow be able to be inferred from the function pointer that I specify (or maybe even the parameter list, but I think that it probably is too far down the line).
My first thought was to defer the conversion to a template parameter value, by passing a template typename and then convert to a value after the fact though template metaprogramming wizardry.
i.e.
template <typename F, typename P>
auto function(P) -> [[ something here to get otherType<P, fn> if F was a function pointer ]]
However, I'm not sure how I can do this. Any ideas?
Edit
What I'm trying to accomplish here is to make a helper function that will generate a class object. So, given what was said by StenSoft, this is what I've come up with. Unfortunately it doesn't work with a failure inside the main() function where it cannot match to the correct function due to deduction failure:
#include <iostream>
#include <functional>
template<typename T, typename F>
struct wrapper_fntor
{
T m_t;
F m_f;
wrapper_fntor(T t, F f) : m_t(t), m_f(f) {}
void invoke() { m_f(m_t); }
};
template<typename T, void(*fn)(T)>
struct wrapper_fn
{
T m_t;
wrapper_fn(T t) : m_t(t) {}
void invoke() { fn(m_t); }
};
template <typename T>
struct Wrapper;
template <typename Ret, typename P>
struct Wrapper<Ret(P)>
{
template <Ret(*fn)(P)>
static Ret function(P p)
{
return fn(std::forward<P>(p));
}
template <Ret(*fn)(P)>
static P get_param_type(P);
typedef decltype(get_param_type<Ret(P)>()) param_t;
};
template<typename F>
wrapper_fn<typename Wrapper<F>::param_t, &Wrapper<F>::function> make_wrapper(typename Wrapper<F>::param_t param)
{
return wrapper_fn<typename Wrapper<F>::param_t, &Wrapper<F>::function>(param);
}
template<typename F>
wrapper_fntor<typename Wrapper<F>::param_t, F> make_wrapper(typename Wrapper<F>::param_t param, F fntor)
{
return wrapper_fntor<typename Wrapper<F>::param_t, F>(param, fntor);
}
void function(int value)
{
std::cout << "function called " << value << std::endl;
}
int main()
{
auto x = make_wrapper<function>(3);
x.invoke();
}
demo
For a similar problem I have used a templated function inside a templated wrapper class and a macro (this actually works with any parameters and return type):
template <typename T>
struct Wrapper;
template <typename Ret, typename... Params>
struct Wrapper<Ret(Params...)>
{
template <Ret(*fn)(Params...)>
static Ret function(Params... params)
{
return fn(std::forward<Params>(params)...);
}
};
#define FUNCTION(fn) \
Wrapper<decltype(fn)>::function<fn>

Howto check a type for the existence of parameterless operator()

I'm trying to check whether a functor is compatible with a given set of parametertypes and a given return type (that is, the given parametertypes can be implicitely converted to the actual parametertypes and the other way around for the return type). Currently I use the following code for this:
template<typename T, typename R, template<typename U, typename V> class Comparer>
struct check_type
{ enum {value = Comparer<T, R>::value}; };
template<typename T, typename Return, typename... Args>
struct is_functor_compatible
{
struct base: public T
{
using T::operator();
std::false_type operator()(...)const;
};
enum {value = check_type<decltype(std::declval<base>()(std::declval<Args>()...)), Return, std::is_convertible>::value};
};
check_type<T, V, Comparer>
This works quite nicely in the majority of cases, however it fails to compile when I'm testing parameterless functors like struct foo{ int operator()() const;};, beccause in that case the two operator() of base are apperently ambigous, leading to something like this:
error: call of '(is_functor_compatible<foo, void>::base) ()' is ambiguous
note: candidates are:
note: std::false_type is_functor_compatible<T, Return, Args>::base::operator()(...) const [with T = foo, Return = void, Args = {}, std::false_type = std::integral_constant<bool, false>]
note: int foo::operator()() const
So obvoiusly I need a different way to check this for parameterless functors. I tried making a partial specialization of is_functor_compatible for an empty parameterpack, where I check if the type of &T::operator() is a parameterless memberfunction, which works more or less. However this approach obviously fails when the tested functor has several operator().
Therefore my question is if there is a better way to test for the existence of a parameterless operator() and how to do it.
When I want to test if a given expression is valid for a type, I use a structure similar to this one:
template <typename T>
struct is_callable_without_parameters {
private:
template <typename T1>
static decltype(std::declval<T1>()(), void(), 0) test(int);
template <typename>
static void test(...);
public:
enum { value = !std::is_void<decltype(test<T>(0))>::value };
};
Have you tried something like:
template<size_t>
class Discrim
{
};
template<typename T>
std::true_type hasFunctionCallOper( T*, Discrim<sizeof(T()())>* );
template<typename T>
std::false_type hasFunctionCallOper( T*, ... );
After, you discriminate on the return type of
hasFunctionCallOper((T*)0, 0).
EDITED (thanks to the suggestion of R. Martinho Fernandes):
Here's the code that works:
template<size_t n>
class CallOpDiscrim {};
template<typename T>
TrueType hasCallOp( T*, CallOpDiscrim< sizeof( (*((T const*)0))(), 1 ) > const* );
template<typename T>
FalseType hasCallOp( T* ... );
template<typename T, bool hasCallOp>
class TestImpl;
template<typename T>
class TestImpl<T, false>
{
public:
void doTellIt() { std::cout << typeid(T).name() << " does not have operator()" << std::endl; }
};
template<typename T>
class TestImpl<T, true>
{
public:
void doTellIt() { std::cout << typeid(T).name() << " has operator()" << std::endl; }
};
template<typename T>
class Test : private TestImpl<T, sizeof(hasCallOp<T>(0, 0)) == sizeof(TrueType)>
{
public:
void tellIt() { this->doTellIt(); }
};