SFINAE | strange behaviour - c++

I am studying SFINAE and c++ in general. I'm having a strange behaviour with My SFINAE macros (called here "annotations"):
<lang/Annotations.h>
#pragma once
#define ENABLE_IF(y) typename std::enable_if<y,std::nullptr_t>::type
#define IS_REFERENCE(x) std::is_reference<x>::value
#define IS_CONSTRUCTIBLE(...) std::is_constructible<__VA_ARGS__>::value
I made a custom "MY_OBJECT" class, which provides the following constructor:
MY_OBJECT(const char* stringDataPtr) noexcept;
The objective here is the following:
By using a variadic template function, each template argument's type must be checked: if it can be passed to String constructor (std::is_constructible) then a message "is constructible" must be printed, otherwise "is not constructible" must be printed.
The problem
Even by passing int values, my SFINAE method does not get "SFINAE'd" and I always get "Is constructible" message.
<util/SFINAETools.h
namespace SFINAETools {
enum class SFINAEResult {
IS_CONSTRUCTIBLE,
IS_NOT_CONSTRUCTIBLE,
IS_REFERENCE,
IS_NOT_REFERENCE
};
std::ostream& operator<<(std::ostream& out, const SFINAEResult& value) {
static std::unordered_map<SFINAEResult, System::MyString> strings {
{SFINAEResult::IS_CONSTRUCTIBLE, "IS_CONSTRUCTIBLE"},
{SFINAEResult::IS_NOT_CONSTRUCTIBLE, "IS_NOT_CONSTRUCTIBLE"},
{SFINAEResult::IS_REFERENCE, "IS_REFERENCE"},
{SFINAEResult::IS_NOT_REFERENCE, "IS_NOT_REFERENCE"}
};
return out << strings[value];
}
class SFINAECallbackHandler : public Object {
public:
virtual void onSFINAEResult(const SFINAEResult& result) const = 0;
};
template <typename... ARGS, ENABLE_IF(IS_CONSTRUCTIBLE(ARGS...))>
void executeIfConstructible(const SFINAECallbackHandler& callBackHandler) {
callBackHandler.onSFINAEResult(SFINAEResult::IS_CONSTRUCTIBLE);
}
template <typename... ARGS, ENABLE_IF(!IS_CONSTRUCTIBLE(ARGS...))>
void executeIfConstructible(const SFINAECallbackHandler& callBackHandler) {
callBackHandler.onSFINAEResult(SFINAEResult::IS_NOT_CONSTRUCTIBLE);
}
template <typename X, ENABLE_IF(IS_REFERENCE(X))>
void executeIfIsReference(const SFINAECallbackHandler& callBackHandler) {
callBackHandler.onSFINAEResult(SFINAEResult::IS_REFERENCE);
}
template <typename X, ENABLE_IF(!IS_REFERENCE(X))>
void executeIfIsReference(const SFINAECallbackHandler& callBackHandler) {
callBackHandler.onSFINAEResult(SFINAEResult::IS_NOT_REFERENCE);
}
};
MAIN.cpp
#include <lang/CppApplication.h>
#include <util/SFINAETools.h>
class MyCallbackHandler :public SFINAETools::SFINAECallbackHandler {
public:
virtual void onSFINAEResult(const SFINAETools::SFINAEResult& result) const override {
std::cout << result << std::endl;
}
};
class MY_OBJECT : public Object {
public:
MY_OBJECT(const char* strDataPtr) {
}
};
class Main : public CppApplication {
public:
virtual int main(const std::vector<String>& arguments) override {
createString(1, "2");
return 0;
}
template <typename Arg1>
void createString(Arg1&& arg1) {
SFINAETools::executeIfConstructible<MY_OBJECT, Arg1>(MyCallbackHandler());
}
template <typename Arg1, typename ...Args>
void createString(Arg1&& arg1, Args&&... args) {
createString(arg1);
createString(args...);
}
template <typename ...Args>
void createString(Args&&... args) {
std::list<MY_OBJECT> list;
createString(list, args...);
}
};

I don't know if it is the problem (the only problem) but this macro
#define ENABLE_IF(y) typename std::enable_if<y>::type
becomes void when y is true.
So when y is true
template <typename... Types, ENABLE_IF(!IS_CONSTRUCTIBLE(Types...)) = 0>
becomes
template <typename... Types, void = 0>
That can't work. 0 isn't a valid value for void. There are no valid values for void.
And
template <typename X, ENABLE_IF(IS_REFERENCE(X))>
becomes
template <typename X, void>
That is even worse.
I suppose you can define ENABLE_IF to return (in this case) an int
// ...........................................VVVVV
#define ENABLE_IF(y) typename std::enable_if<y, int>::type
remembering the = 0 after every ENABLE_IF
Another problem: now you have
template <typename X, typename Y>
static bool executeIfConstructible(std::function<void()> predicate) {
predicate();
return true;
}
template <typename X, typename Y , ENABLE_IF(!IS_CONSTRUCTIBLE(X,Y))>
static bool executeIfConstructible(std::function<void()> predicate) {
return false;
}
So you have two version of executeIfContructible(): the first one always enabled, the second one enabled only when !IS_CONSTRUCTIBLE(X,Y) is true.
You have to disable the first one when !IS_CONSTRUCTIBLE(X,Y) is false (when IS_CONSTRUCTIBLE(X,Y)) or you'll have an ambiguous call when the second one is enabled.
template <typename X, typename Y , ENABLE_IF(IS_CONSTRUCTIBLE(X,Y))>
static bool executeIfConstructible(std::function<void()> predicate) {
predicate();
return true;
}
template <typename X, typename Y , ENABLE_IF(!IS_CONSTRUCTIBLE(X,Y))>
static bool executeIfConstructible(std::function<void()> predicate) {
return false;
}
Unrequested suggestion: C-style macros are distilled evil. Avoid C-style macros when you can.
For example, instead a macro for ENABLE_IF, define a using
template <bool B>
using EnableIf = typename std::enable_if<B, int>::type;
For IS_REFERENCE and IS_CONSTRUCTIBLE—if you are sure you need them—you can define (starting from C++14) a couple of constexpr template variables
template <bool B>
constexpr bool IsReference = std::is_reference<B>::value;
template <typename ... Ts>
constexpr bool IsConstructible = std::is_constructible<Ts...>::value;

Related

How to detect the existence of a function (NOT class member) with a specific name and signature using type_traits in C++17

Trying to accomplish the following:
// Template not necessary, but shows the pattern
template <typename T>
bool MyFunction(const T&, const uint8_t);
template <T>
struct is_myfunc_defined : std::false_type{}
// How do I properly create this
template <typname R, typename... Args>
struct is_myfunc_defined<R MyFunction(args....)> : std::true_type
{
};
struct MyStruct1 {};
struct MyStruct2 {};
// Will Match
bool MyFunction(const MyStruct&, const uint8_t){ return true; }
// Will not match
bool ShouldFail1(const MyStruct2&, const uint8_t){ return true; }
void MyFunction(const MyStruct2&, const uint8_t){ return true; }
bool MyFunction(const MyStruct2&){ return true; }
int main()
{
cout << is_myfunc_defined<MyStruct>::value << endl; // true
cout << is_myfunc_defined<MyStruct2>::value << endl; // false
}
I know how to use is_detected_exact to check for a class method with a specific return type, name, and signature, but how does one do it with a straight up function. Can't figured it out, need help.
Thanks!
I know how to use is_detected_exact to check for a class method
It's no different for a global function:
template <typename ...P>
using detect_myfunc = decltype(MyFunction(std::declval<P>()...));
template <typename T>
struct is_myfunc_defined {};
template <typename R, typename ...P>
struct is_myfunc_defined<R(P...)>
: std::experimental::is_detected_exact<R,detect_myfunc,P...> {};
{};

Achieve functor overloading through composition

Given some existing functors:
struct incr {
int operator()(int x) const { return x + 1; }
};
struct rep_str {
std::string operator()(const std::string& s) const { return s + s; }
};
I'm wondering if it's possible to achieve something like this:
auto f = overload<incr, rep_str>();
f(1); // returns 2
f("hello"); // returns "hellohello"
Multiple overloads may look like:
auto f = overload<fa, fb, fc, ...>();
// or...
auto g = overload<fa, overload<fb, overload<fc, ...>>>();
I'm thinking maybe use SFINAE with std::result_of_t or something like that, but haven't figured out how.
You don't need anything too fancy: just inherit from all the arguments and use using-declarations to bring in operator() from the base classes. However, in the variadic case, you can't have a pack expansion in a using-declaration, so you have to use a recursive approach, like so:
template <class... Ts>
struct overload {}; // only used for empty pack
template <class T>
struct overload<T> : private T {
using T::operator();
};
template <class T1, class T2, class... Ts>
struct overload<T1, T2, Ts...> : private T1, overload<T2, Ts...> {
using T1::operator();
using overload<T2, Ts...>::operator();
};
Brian's answer is better, IMHO, but since I worked on it, here's mine:
#include <type_traits>
#include <utility>
template <typename... Fns>
struct overload;
template <typename Fn, typename... Fns>
struct overload<Fn, Fns...>
{
template <typename... T>
std::result_of_t<Fn(T...)> operator()(T && ... args) const {
return Fn()(std::forward<T>(args)...);
}
using next = overload<Fns...>;
template <typename... T>
std::result_of_t<next(T...)> operator()(T && ... args) const {
return next()(std::forward<T>(args)...);
}
};
this can be done using template specialization:
#include <string>
#include <iostream>
template <typename...Args>
struct overload{
};
template <> struct overload<int>{
int operator()(int x) const { return x + 1; }
};
template <> struct overload< std::string>{
std::string operator()(const std::string& s) const { return s + s; }
};
template <typename...Args >
auto f(Args...arg){
overload<Args...> func;
return func(arg...);
}
int main()
{
std::cout << f(3) << std::endl << f(std::string("Hello"));
}
Note: two answers by #Brian and #md5i more general and elegant and perfect and better than this.

How to implement overloaded functions using templates in C++?

Suppose I want to define a set of functions, each having 4 overloads, the first overload taking a single parameter of type int32_t and the second taking int64_t, the third - uint32_t and the fourth - uint64_t. For each function, all overloads have the same implementation so I could define a function template instead:
template <typename T>
void f(T t) {
// ...
}
However this is different from having four overloads because now I have a separate function for each (integer) type that can be used to instantiate f. The implementation details of f are such that it might not work for other integral types however. To address this I can wrap the function template in four overloaded functions:
template <typename T>
void f_impl(T t) {
// ...
}
void f(int32_t value) { f_impl(value); }
void f(int64_t value) { f_impl(value); }
void f(uint32_t value) { f_impl(value); }
void f(uint64_t value) { f_impl(value); }
It works but requires substantial amount of code for each function (4 function overloads + 1 function template). Is there a way to simplify this?
To clarify, it is not desirable to use template directly because it doesn't make sense (for implementation reasons or otherwise) to have its specializations for types other than int32_t, int64_t, uint32_t and uint64_t.
I've tried using std::enable_if already and the problem with it is best illustrated by this example:
#include <type_traits>
#include <iostream>
template <typename T>
struct is_supported_int {
static const bool value = false;
};
template <>
struct is_supported_int<int32_t> {
static const bool value = true;
};
template <>
struct is_supported_int<int64_t> {
static const bool value = true;
};
// ...
template <typename T, typename = typename std::enable_if<is_supported_int<T>::value, T>::type>
void f(T t) {
// ...
}
int main() {
short s = 42;
f(s);
}
Unlike in the original version with overloads which I'm trying to emulate, this example will not compile since f will be excluded from the set of matching functions for short.
Unfortunately std::is_integral<T> as suggested by Rapptz doesn't help either because due to implementation details of f this function can only be defined for specific types, not for all integral types.
Something like this would work.
#include <type_traits>
#include <iostream>
template<typename T, typename = typename std::enable_if<std::is_integral<T>::value, T>::type>
void f(T t) {
std::cout << "int types only!\n";
}
int main() {
f(1.234f);
f(12);
}
f(1.234f) would fail to compile but f(12) wouldn't.
Use enable_if or a static assert to restrict instantiation.
#include <type_traits>
#include <cstdint>
template<bool X, bool Y>
struct or_ : std::true_type
{};
template<>
struct or_<false, false> : std::false_type
{};
template<typename T>
struct valid_type_for_f :
or_< std::is_same<T, std::uint32_t>::value,
std::is_same<T, std::uint64_t>::value> // etc.
{};
// static assert
template<typename T>
T f(T t) {
static_assert(valid_type_for_f<T>::value, "Not a valid type");
return t;
}
// enable_if
template<typename T>
typename std::enable_if<valid_type_for_f<T>::value, T>::type
fenable(T t) {
return t;
}
int main()
{
float x = 4.2f;
f(x); // fails
fenable(x); // fails
std::uint32_t xx = 23;
f(xx);
fenable(xx);
return 0;
}

How do I make this template argument variadic?

Say I have a template declaration like this:
template <class A, class B, class C = A (&)(B)>
How would I make it so that I could have a variable amount of objects of type C? Doing class C ...c = x won't work because variadic template arguments can't have default values. So this is what I've tried:
template <typename T>
struct helper;
template <typename F, typename B>
struct helper<F(B)> {
typedef F (&type)(B);
};
template <class F, class B, typename helper<F(B)>::type ... C>
void f(C ...c) { // error
}
But up to the last part I get error messages. I don't think I'm doing this right. What am I doing wrong here?
I think you can use the following approach. First, some machinery for type traits. This allows you to determine if the types in an argument pack are homogeneous (I guess you want all functions to have the same signature):
struct null_type { };
// Declare primary template
template<typename... Ts>
struct homogeneous_type;
// Base step
template<typename T>
struct homogeneous_type<T>
{
using type = T;
static const bool isHomogeneous = true;
};
// Induction step
template<typename T, typename... Ts>
struct homogeneous_type<T, Ts...>
{
// The underlying type of the tail of the parameter pack
using type_of_remaining_parameters = typename
homogeneous_type<Ts...>::type;
// True if each parameter in the pack has the same type
static const bool isHomogeneous =
is_same<T, type_of_remaining_parameters>::value;
// If isHomogeneous is "false", the underlying type is a fictitious type
using type = typename conditional<isHomogeneous, T, null_type>::type;
};
// Meta-function to determine if a parameter pack is homogeneous
template<typename... Ts>
struct is_homogeneous_pack
{
static const bool value = homogeneous_type<Ts...>::isHomogeneous;
};
Then, some more type traits to figure out the signature of a generic function:
template<typename T>
struct signature;
template<typename A, typename B>
struct signature<A (&)(B)>
{
using ret_type = A;
using arg_type = B;
};
And finally, this is how you would define your variadic function template:
template <typename... F>
void foo(F&&... f)
{
static_assert(is_homogeneous_pack<F...>::value, "Not homogeneous!");
using fxn_type = typename homogeneous_type<F...>::type;
// This was template parameter A in your original code
using ret_type = typename signature<fxn_type>::ret_type;
// This was template parameter B in your original code
using arg_type = typename signature<fxn_type>::arg_type;
// ...
}
Here is a short test:
int fxn1(double) { }
int fxn2(double) { }
int fxn3(string) { }
int main()
{
foo(fxn1, fxn2); // OK
foo(fxn1, fxn2, fxn3); // ERROR! not homogeneous signatures
return 0;
}
Finally, if you need an inspiration on what to do once you have that argument pack, you can check out a small library I wrote (from which part of the machinery used in this answer is taken). An easy way to call all the functions in the argument pack F... f is the following (credits to #MarkGlisse):
initializer_list<int>{(f(forward<ArgType>(arg)), 0)...};
You can easily wrap that in a macro (just see Mark's answer to the link I posted).
Here is a complete, compilable program:
#include <iostream>
#include <type_traits>
using namespace std;
struct null_type { };
// Declare primary template
template<typename... Ts>
struct homogeneous_type;
// Base step
template<typename T>
struct homogeneous_type<T>
{
using type = T;
static const bool isHomogeneous = true;
};
// Induction step
template<typename T, typename... Ts>
struct homogeneous_type<T, Ts...>
{
// The underlying type of the tail of the parameter pack
using type_of_remaining_parameters = typename
homogeneous_type<Ts...>::type;
// True if each parameter in the pack has the same type
static const bool isHomogeneous =
is_same<T, type_of_remaining_parameters>::value;
// If isHomogeneous is "false", the underlying type is a fictitious type
using type = typename conditional<isHomogeneous, T, null_type>::type;
};
// Meta-function to determine if a parameter pack is homogeneous
template<typename... Ts>
struct is_homogeneous_pack
{
static const bool value = homogeneous_type<Ts...>::isHomogeneous;
};
template<typename T>
struct signature;
template<typename A, typename B>
struct signature<A (&)(B)>
{
using ret_type = A;
using arg_type = B;
};
template <typename F>
void foo(F&& f)
{
cout << f(42) << endl;
}
template <typename... F>
void foo(typename homogeneous_type<F...>::type f, F&&... fs)
{
static_assert(is_homogeneous_pack<F...>::value, "Not homogeneous!");
using fxn_type = typename homogeneous_type<F...>::type;
// This was template parameter A in your original code
using ret_type = typename signature<fxn_type>::ret_type;
// This was template parameter B in your original code
using arg_type = typename signature<fxn_type>::arg_type;
cout << f(42) << endl;
foo(fs...);
}
int fxn1(double i) { return i + 1; }
int fxn2(double i) { return i * 2; }
int fxn3(double i) { return i / 2; }
int fxn4(string s) { return 0; }
int main()
{
foo(fxn1, fxn2, fxn3); // OK
// foo(fxn1, fxn2, fxn4); // ERROR! not homogeneous signatures
return 0;
}
template <typename T>
struct helper;
template <typename F, typename B>
struct helper<F(B)> {
typedef F (*type)(B);
};
template<class F, class B>
void f()
{
}
template <class F, class B, typename... C>
void f(typename helper<F(B)>::type x, C... c)
{
std::cout << x(B(10)) << '\n';
f<F,B>(c...);
}
int identity(int i) { return i; }
int half(int i) { return i/2; }
int square(int i) { return i * i; }
int cube(int i) { return i * i * i; }
int main()
{
f<int,int>(identity,half,square,cube);
}
Here's a modified version that can deduce types:
template<class F, class B>
void f(F(*x)(B))
{
x(B());
}
template <class F, class B, typename... C>
void f(F(*x)(B), C... c)
{
f(x);
f<F,B>(c...);
}
int identity(int i) { return i; }
int half(int i) { return i/2; }
int square(int i) { return i * i; }
int cube(int i) { return i * i * i; }
int string_to_int(std::string) { return 42; }
int main()
{
f(identity,half,square,cube);
// f(identity,half,string_to_int);
}

Ambiguous template arguments not excluded by enable_if

I want to automatically choose the right pointer-to-member among overloaded ones based on the "type" of the member, by removing specializations that accept unconcerned members (via enable_if).
I have the following code:
class test;
enum Type
{
INT_1,
FLOAT_1,
UINT_1,
CHAR_1,
BOOL_1,
INT_2,
FLOAT_2,
UINT_2,
CHAR_2,
BOOL_2
};
template<typename T, Type Et, typename func> struct SetterOk { static const bool value = false; };
template<typename T> struct SetterOk<T,INT_1,void (T::*)(int)> { static const bool value = true; };
template<typename T> struct SetterOk<T,FLOAT_1,void (T::*)(float)> { static const bool value = true; };
template<typename T> struct SetterOk<T,UINT_1,void (T::*)(unsigned int)> { static const bool value = true; };
template<typename T> struct SetterOk<T,CHAR_1,void (T::*)(char)> { static const bool value = true; };
template<typename T> struct SetterOk<T,BOOL_1,void (T::*)(bool)> { static const bool value = true; };
template<typename T> struct SetterOk<T,INT_2,void (T::*)(int,int)> { static const bool value = true; };
template<typename T> struct SetterOk<T,FLOAT_2,void (T::*)(float,float)> { static const bool value = true; };
template<typename T> struct SetterOk<T,UINT_2,void (T::*)(unsigned int, unsigned int)> { static const bool value = true; };
template<typename T> struct SetterOk<T,CHAR_2,void (T::*)(char,char)> { static const bool value = true; };
template<typename T> struct SetterOk<T,BOOL_2,void (T::*)(bool,bool)> { static const bool value = true; };
template <bool, class T = void> struct enable_if {};
template <class T> struct enable_if<true, T> { typedef T type; };
template<typename T, Type Et>
struct Helper
{
template<typename U>
static void func(U method, typename enable_if<SetterOk<T,Et,U>::value>::type* dummy = 0)
{
}
};
class test
{
public:
void init()
{
Helper<test,INT_2>::func(&test::set);
}
void set2(int);
void set(int);
void set(int,int);
void set(float,float);
};
int main()
{
test t;
t.init();
return 0;
}
I'm expecting it to choose the right function between all possible. The problem is that the compiler says "cannot deduce template argument as function argument is ambiguous".
It seems I don't know how to use enable_if, because if so the compiler would only allow the specialization if the specified function has the right type...
Note that I want to have C++03 solutions (if possible) - my code must compile on some old compilers.
Thanks in advance
You can never refer to an overloaded function without disambiguating it (means: static_casting it to the correct type). When you instantiate Helper::func the type of the function argument cannot be known without ever disambiguating it.
The reason it doesn't compile is quite simply that there are several different overloaded functions and it doesn't know which one you mean. Granted, only one of these (void set(int,int)) would actually compile, given the specialization Helper<test,INT_2>. However, this is not enough for the compiler to go on.
One way of getting this to compile would be to explicitly cast &test::set to the appropriate type:
Helper<test,INT_2>::func(static_cast<void (test::*)(int,int)>(&test::set));
Another way would be to use explicit template specialization:
Helper<test,INT_2>::func<void (test::*)(int,int)>((&test::set));
Either way, you need to let the compiler know which of the set functions you are trying to refer to.
EDIT:
As I understand it, you want to be able to deduce, from the use of a Type, which function type should be used. The following alternative achieves this:
template<typename T, Type Et> struct SetterOK{};
template<typename T> struct SetterOK<T,INT_1> {typedef void (T::*setter_type)(int);};
template<typename T> struct SetterOK<T,FLOAT_1> {typedef void (T::*setter_type) (float);};
// ...
template<typename T> struct SetterOK<T,INT_2> {typedef void (T::*setter_type)(int,int);};
// ....
template<typename T, Type Et>
struct Helper
{
template<typename U>
static void func(U method)
{
}
};
class test
{
public:
void init()
{
Helper<test,INT_2>::func<SetterOK<test,INT_2>::setter_type >(&test::set);
}
void set2(int);
void set(int);
void set(int,int);
void set(float,float);
};
int main()
{
test t;
t.init();
return 0;
}
ADDITIONAL EDIT:
A thought just occurred to me. In this special case which you've done, where U is SetterOK::setter_type, things can be simplified further by completely removing the template arguments for func:
static void func(typename SetterOK<T,Et>::setter_type method)
{
}
This would make the init method a simpler:
void init()
{
Helper<test,INT_2>::func(&test::set);
}