Macro for (SFINAEd) template function - c++

#define BINDINGTEMPLATE template<typename T, typename = typename std::enable_if_t < std::is_same_v<typename std::decay_t<T>, int> || std::is_same_v<typename std::decay_t<T>, std::string> || std::is_same_v<typename std::decay_t<T>, char>>>
Is something like this bad practice?
I am using this function template many times within the same class.
BINDINGTEMPLATE
void myFunction(int x, int y)
{
// do something specialised based on input template
}
For instance, I need to use it in many functions, like this one :

Yes, it's a bad practice. Don't use macros for something that can easily be done without them.
You can move that long SFINAE condition into something like
template <typename T> using foo = std::enable_if_t<...>;
And then you can write simply:
template <typename T, typename = foo<T>>
void myFunction(int x, int y)
Alternatively, you could put the condition into a constexpr function or variable template, then write enable_if_t every time you use it.
Also you could use a concept (requires C++20):
template <typename T>
concept foo = std::is_same_v<typename std::decay_t<T>, int> || etc;
template <foo T>
void myFunction(int x, int y)
Note that this use of enable_if_t (regardless of whether you're using a helper using or not) is not very robust, as the user can circumvent it by explicitly specifying the second template parameter.
A better approach is:
template <typename T, std::enable_if_t<..., std::nullptr_t> = nullptr>
void myFunction(int x, int y)
In addition to being foolproof, this also lets you overload the function based on different traits.
The concepts also solve both problems.

You can achieve the same with a type-trait:
template <typename T>
using enable_if_int_or_string_or_char = std::enable_if_t <
std::is_same_v<typename std::decay_t<T>, int>
|| std::is_same_v<typename std::decay_t<T>, std::string>
|| std::is_same_v<typename std::decay_t<T>, char>>;
Instead of the macro you can then use enable_if_int_or_string_or_char<T>. Macros have severe downsides, so the best macro is the one that you do not need to use.

IMHO, macros are distilled evil.
So, yes: (IMHO) is bad practice.
I propose another way (just for fun: the other answers show good solutions) to avoid it.
You can declare a foo() (SFINAE enabled/disabled function) as follows
template <typename T>
std::enable_if_t<std::is_same_v<std::decay_t<T>, int>
|| std::is_same_v<std::decay_t<T>, std::string>
|| std::is_same_v<std::decay_t<T>, char>> foo ();
you can write your final function using it
template <typename T>
decltype(foo<T>()) bar (int, int)
{ }
The following is a full compiling example
#include <string>
#include <type_traits>
template <typename T>
std::enable_if_t<std::is_same_v<std::decay_t<T>, int>
|| std::is_same_v<std::decay_t<T>, std::string>
|| std::is_same_v<std::decay_t<T>, char>> foo ();
template <typename T>
decltype(foo<T>()) bar (int, int)
{ }
int main ()
{
bar<int>(0, 0); // compile
// bar<long>(0, 0); // compilation error
}

This is an example of trait checking if the type is one of the types you look for:
template <typename T>
struct is_int_string_char
{
static const bool value = std::is_same<std::decay<T>::type, int>
|| std::is_same<std::decay<T>::type, std::string>
|| std::is_same<std::decay<T>::type, char>;
};
You can use it as a constant at compilation type with is_int_string_char<MyType>::value. In your case (if I well understand your code), you can simplify it with:
template <typename T, typename U = std::enable_if<is_int_string_char<T>>

Since C++ provides many other options to solve this, one should not go for macros(IMO).
For instance, you could make a variable template, where you can specify that any of the passed template Types is same as myFunction's template type T, and SFNIAE the solution.
Thanks to c++17's std::disjunction, by which this idea can be generalized for any arbitary number of Types, with less noisy!
#include <string>
#include <type_traits> // std::enable_if_t, std::is_same, std::disjunction_v
template<typename T, typename... Types>
constexpr bool isAcceptableType = std::disjunction_v<std::is_same<T, Types>...>;
template <typename T>
auto myFunction(T x, T y) -> std::enable_if_t<isAcceptableType<T, char, std::string, int>>
{
// do something
}
See a demo

People yelling macros are evil are similar to those yelling goto is evil.
Since SFINAE until C++20 is really ugly, macros are a good way to make it more user friendly. But, the macro you provide is indeed bad practice: It's way too long.
I regularly use the following two macros REQUIRES and CONCEPT, named after C++20 concepts, for quite some time already:
#define REQUIRES( ... ) typename std::enable_if< __VA_ARGS__, bool >::type = false
template< typename T > constexpr bool always_true = true;
#define CONCEPT( ... ) always_true< __VA_ARGS__ >
Two notes:
Although the macro actually only take one argument, I use __VA_ARGS__ so that commata are handled correctly when used. Otherwise, people would have to double parenthise expressions involving a comma.
The always_true template is similar to void_t, but I wrote these macros before I knew about void_t.
Usage examples:
template< typename T, REQUIRES( std::is_arithmetic<T>::value && sizeof(T)>=4 ) >
void f( T t );
template< typename T,
REQUIRES( std::is_integral<T>::value ),
REQUIRES( sizeof(T)>=4 ) >
struct BigIntConcept;
template< typename T, REQUIRES( CONCEPT( BigIntConcept<T> ) ) >
void f( T t );
[+] One of the greatest benefits of this macro is: Even people which do not understand SFINAE can read/understand it, but also use it.
[-] The only downside I found so far is: The macros work nearly only for SFINAE in the template-parameter-declaration place (I am sure there is a word for this).

Related

Can a self-contained C++ concept match a particular template with any arguments?

I'd like to have a C++ concept that matches a particular template type regardless of one of the template arguments. I can, of course, do this using some other helper declarations to pick apart the template type. But one of the benefits of concepts and requires expressions in particular is that they eliminate many of the needs for helper types. So I'm wondering if it's possible to do this "all-in-one" with a single concept declaration.
Here's a minimal working example:
#include <algorithm>
#include <compare>
#include <iostream>
#include <memory>
#include <string>
template<typename A> using char_string =
std::basic_string<char, std::char_traits<char>, A>;
using std::string;
template<typename T> struct AltAllocator : std::allocator<T> {};
using AltString = char_string<AltAllocator<char>>;
template<typename T> constexpr bool is_char_string_v = false;
template<typename A> constexpr bool is_char_string_v<char_string<A>> = true;
template<typename T> concept is_char_string = is_char_string_v<T>;
inline bool
operator==(is_char_string auto const &a, is_char_string auto const &b)
{
return std::equal(a.begin(), a.end(), b.begin(), b.end());
}
int
main()
{
string s;
AltString as;
std::cout << std::boolalpha << (s == as) << std::endl;
}
I'm hoping to be able to define is_char_string without having to introduce is_char_string_v. In this particular case, knowing that strings contain their allocator type, I could of course "cheat" with something like this:
template<typename T> concept is_char_string =
std::same_as<T, char_string<typename T::allocator_type>>;
Is there a more general way of writing a self-contained concept that matches some particular template instantiated with any template arguments?
I don't know what the broader problem might be, but we can decompose the problem of checking that something is a basic_string<char, char_traits<char>, A> into the problems of: (1) it's a basic_string and (2) its first two types are char and char_traits<char>.
The first problem is the standard is_specialization_of trait:
template <typename T, template <typename...> class Z>
inline constexpr bool is_specialization_of = false;
template <typename... Args, template <typename...> class Z>
inline constexpr bool is_specialization_of<Z<Args...>, Z> = true;
And the second we can use Boost.Mp11 for general type list manipulation. So either:
template <typename T>
concept char_string = is_specialization_of<T, std::basic_string>
&& std::same_as<mp_first<T>, char>
&& std::same_as<mp_second<T>, std::char_traits<char>>;
Or check the latter two together:
template <typename T>
concept char_string = is_specialization_of<T, std::basic_string>
&& std::same_as<
mp_take_c<T, 2>
std::basic_string<char, std::char_traits<char>
>;
It's safe to just take the first two parameters here, since the third one is defaulted. And since the second one is also defaulted, you could instead compare to std::string instead of std::basic_string<char, std::char_traits<char>.
If the intent is really to avoid any dependencies or any additional types, then I suppose you could write this:
template <typename T>
concept char_string = requires (T t) {
[]<typename A>(std::basic_string<char, std::char_traits<char>, A>){}(t);
};
But I'm not sure that's a good idea.

Does there exist a type level left-fold metafunction in the standard library?

If a,b,c,.. denote types then let (a,b) be the type std::pair<a,b> I am looking for the map, F, such that
F : ((((a,b),c),d),...))) -> std::tuple<a,b,c,d...>
Does this exist under some existing name in the standard library? If not, is there another library
in which it does or is this easily implemented and I'm just too dumb to know how to do it?
I think this one basically has to be recursive. There is no such thing in the standard library, and for once I can't come up with a Boost.Mp11 one-liner.
namespace impl {
template <typename T>
struct unfold_t {
using type = std::tuple<T>;
};
template <typename A, typename B>
struct unfold_t<std::pair<A, B>> {
using type = mp_push_back<typename unfold_t<A>::type, B>;
};
}
template <typename T>
using unfold = typename impl::unfold_t<T>::type;
With an assist from T.C., the newest edition of Mp11 (1.73) has an algorithm named mp_iterate which we can use thusly.
Given std::pair<std::pair<X, Y>, Z>, if we apply mp_first repeatedly (as R) we get the sequence:
std::pair<std::pair<X, Y>, Z>
std::pair<X, Y>
X
Then, if we apply mp_second to that sequence, we get:
Z
Y
ill-formed
That's pretty close. We do need that X. So we need a more complex metafunction for F: we need to get the second value if possible. There's a metafunction for that:
template <typename L>
using second_or_self = mp_eval_or<L, mp_second, L>;
And now mp_iterate<T, second_or_self, mp_first> gives us mp_list<Z, Y, X>. All we need to do at that point is reverse it and turn it into a std::tuple:
template <typename L>
using unfold = mp_rename<mp_reverse<
mp_iterate<L, second_or_self, mp_first>>,
std::tuple>;
Now that Boost.173 is on compiler-explorer, demo.
Or, I suppose, if you really hate your readers, you can make this a single alias:
template <typename L>
using unfold = mp_rename<mp_reverse<
mp_iterate_q<L,
mp_bind<mp_eval_or_q, _1, mp_quote<mp_second>, _1>,
mp_quote<mp_first>>>,
std::tuple>;
I like the solution by #Barry, and in particular the name unfold for this meta-function. However, I think you can implement this quite easily using partial specializations, without using boost.Mp11, and you might find this easier to understand.
First, provide the base case for a type that's already completely unfolded into a tuple:
template <typename ...Ts>
struct unfold_impl { using type = std::tuple<Ts...>; };
and then provide a specialization if there's still a pair left to unfold:
template <typename A, typename B, typename ...Ts>
struct unfold_impl<std::pair<A,B>, Ts...> : unfold_impl<A, B, Ts...> {};
and finally provide a convenience alias template:
template <typename ...Ts>
using unfold = typename unfold_impl<Ts...>::type;
and that's it.
You can check that it works, like this:
static_assert(
std::is_same_v<
unfold<std::pair<std::pair<std::pair<int, long>, char>, double>>,
std::tuple<int, long, char, double>
>);
Here's a demo

Template matching two (seemingly) unrelated types

I have a scoped enum:
enum class E
{ A, B, C };
Now I want to have a function, which accepts a value of that scoped int OR an int itself.
It should be something like:
template <typename T, std::enable_if_t<std::is_same<T, enum E **OR** int>::value, int> = 0 >
void foo(T value);
But I don't know how to deal with the concept of OR in C++ templates. I know std::is_convertible, however I don't even know, if I could use it here, because you can only static_cast scoped enums to int.
But anyway I don't want to accept any type that is convertible to int but only types of that single enum or int.
Overload seems the simplest:
void foo(int value);
void foo(E value) { foo(static_cast<int>(value); } // Or specific code
template <typename T> void foo(T) = delete; // To forbid type convertible to int
else you can use SFINAE
template <typename T>
std::enable_if_t<std::is_same<int, T>::value || std::is_same<E, T>::value>
foo(T value);
Because std::is_same<...>::value is a boolean, you can simply use || operator with 2 std::is_same<...>::value :
template <typename T, std::enable_if_t<std::is_same<T, enum E>::value || std::is_same<T, int>::value, int> = 0 >
void foo(T value);
std::is_same instantiations define a constexpr implicit bool conversion, so you can instantiate them and perform logical OR with ||. In C++17, you will also be able to use std::disjunction to similar effect, although this will likely compile slower for only two type traits. Example of both:
#include <type_traits>
enum class E
{ A, B, C };
template <typename T, std::enable_if_t<
std::is_same<T, E>{} || std::is_same<T, int>{},
int> = 0>
void foo(T){
}
//in C++17, you can also do this:
template <typename T, std::enable_if_t<
std::disjunction<std::is_same<T, E>, std::is_same<T, int>>{},
int> = 0>
void bar(T){
}
int main() {
foo(E::A);
foo(0);
//foo('A'); fails
bar(E::A);
bar(0);
//bar('A'); fails
return 0;
}
std::disjunction is the logical OR template you were wondering about (although I recommend using || with std::is_same for your case). Interestingly, std::disjunction even performs logical short-circuiting of template instantiations, just like the humble old || operator does in a runtime context. I believe recent versions of libc++ are already shipping with std::disjunction. If your <type_traits> implementation doesn't have it yet, the example implementation at cppreference works just fine for me. If you get the chance, you should see how it works. It's rather clever!

How to restrict typenames in template

Have a function which can accept 4 different types. And their implementations are very similar.
template< typename T >
void foo( std::string &&name, T value ){
//...
}
typename T must be one of 4 predefined types. Other typenames is not acceptable, and should be restricted at compile-time.
Is it possible to write in C++?
I can think of at least three ways, off the top of my head.
First:
namespace internal {
template< typename T >
void foo_impl( std::string &&name, T value ) {
// actual implementation here
}
}
void foo(std::string &&name, SpecialType1 value ) {
internal::foo_impl(std::forward<std::string>(name), value);
}
void foo(std::string &&name, SpecialType2 value ) {
internal::foo_impl(std::forward<std::string>(name), value);
}
Second:
template< typename T >
typename std::enable_if<std::is_same<T, SpecialType1>::value ||
std::is_same<T, SpecialType2>::value >::type
foo( std::string &&name, T value ){
//implementation here
}
Third:
template< typename T >
void foo(std::string &&name, T value){
static_assert(std::is_same<T, SpecialType1>::value ||
std::is_same<T, SpecialType2>::value,
"wrong template argument");
//implementation here
}
Demo
<type_traits> let you generalize your logic into class template. How this works is we take template parameter T and parameter pack of Ts and we start checking if T is same to Head of the list of types. If match is found, we inherit from std::true_type and we are done. If no match is found, we pop the head and recursively instantiate same template with tail of Ts. Eventually, if no match is found at all, parameter pack size will drop to zero and the compiler will instantiate base template class that inherit from std::false_type. Please check this video for much better and in dept explanation by Mr. Walter E. Brown.
template<class T, class...> struct is_any_of: std::false_type{};
template<class T, class Head, class... Tail>
struct is_any_of<T, Head, Tail...>: std::conditional_t<
std::is_same<T, Head>::value,
std::true_type,
is_any_of<T, Tail...>>
{};
Now we can SFINAE over, using enable_if in almost English wording.
#include <type_traits>
#include <string>
template<
class T,
class = std::enable_if_t<is_any_of<T, int, float, unsigned, double>::value>
>
void foo(std::string &&str, T value) {}
int main()
{
foo(std::string{"hello"}, 3);
foo(std::string{"world"}, '0'); //compile-time error
}
SFANIE is a language feature, a tool, that's used or abused some say to achieve what you ask for,
The standard library component std::enable_if allows for creating a substitution failure in order to enable or disable particular overloads based on a condition evaluated at compile time.
FYI http://en.cppreference.com/w/cpp/language/sfinae.
Note that std::conditional_t<> and std::enable_if_t<> are shorthanded from std::conditional<>::type and std::enable_if<>::type respectively. You could simple replace these in code, but should put typename keyword before enable_if then.
One thing I have seen people done is using std::enable_if. I don't know exactly what your 4 types are, so this is an example with two types int and float.
using myType = std::enable_if<
std::is_same<int, T>::value ||
std::is_same<float, T>::value, T >::type;
myType exists only if T is exactly int or float. Hope that helps!
I know I am late to the party but maybe someone will find this useful.
As of C++20 one can use constraints and concepts to filter possible typenames in a template.
The syntax goes like this:
template <typename T>
requires std::is_integral_v<T>
auto func(T any_integer) {
...
};
// Or, you can also do:
template <typename T>
concept Integer = std::is_integral_v<T>;
template <Integer T>
auto func(T any_integer) {
...
};
// Or, an even better approach:
auto func(Integer auto any_integer) {
...
};
I prefer the last one since it's nice and clean. But, that's just my opinion.
Following are some valid calls to func():
func(int{}); // OK!
func(long{}); // OK!
func(bool{}); // Yes, it's OK too!
func(char{}); // Yes, it's OK too!
Now, some invalid calls to func():
func(double{}); // Compiler error!
func(std::string{}); // Compiler error!
The compiler will also give a clean error message depending on your usage:
note: candidate: ‘template requires is_integral_v void func(T)’
or
note: candidate: ‘template requires Integer auto func(T)’
or
note: candidate: ‘template requires Integerauto:15 auto func(auto:15)’
References:
https://en.cppreference.com/w/cpp/types/is_integral

Check if parameter pack contains a type

I was wondering if C++0x provides any built-in capabilities to check if a parameter pack of a variadic template contains a specific type. Today, boost:::mpl::contains can be used to accomplish this if you are using boost::mpl::vector as a substitute for variadic templates proper. However, it has serious compilation-time overhead. I suppose, C++0x has compiler-level support for std::is_same. So I was thinking if a generalization like below is also supported in the compiler.
template <typename... Args, typename What>
struct is_present
{
enum { value = (What in Args...)? 1 : 0 };
};
Fortunately, the C++ standard has evolved. With C++1z aka C++17, you can finally iterate easily over parameter packs. So the code for the answer is (almost) as simple, as suggested in the question:
template<typename What, typename ... Args>
struct is_present {
static constexpr bool value {(std::is_same_v<What, Args> || ...)};
};
The weird-looking (std::is_same_v<What, Args> || ...) is expanded by the compiler internally to (std::is_same_v<What, Args[0]> || std::is_same_v<What, Args[1]> || ...), which is exactly, what you want. It even correctly yields false with an empty Args parameter pack.
It is even possible to do the whole check inline in a function or method - no helper structs are required anymore:
template<typename T, typename ... List>
void foo(T t, List ... lst)
{
if constexpr((std::is_same_v<T, List> || ...)) {
std::cout << "T is in List" << std::endl;
} else {
std::cout << "T is not in List" << std::endl;
}
}
Note: This has been taken from another question, that was marked as a duplicate of this question. As this is the "canonical" question for this topic, I added that important information here.
No, you have to use (partial) specialization with variadic templates to do compile-time computations like this:
#include <type_traits>
template < typename Tp, typename... List >
struct contains : std::true_type {};
template < typename Tp, typename Head, typename... Rest >
struct contains<Tp, Head, Rest...>
: std::conditional< std::is_same<Tp, Head>::value,
std::true_type,
contains<Tp, Rest...>
>::type {};
template < typename Tp >
struct contains<Tp> : std::false_type {};
There is only one other intrinsic operation for variadic templates and that is the special form of the sizeof operator which computes the length of the parameter list e.g.:
template < typename... Types >
struct typelist_len
{
const static size_t value = sizeof...(Types);
};
Where are you getting "it has serious compilation-time overhead" with boost mpl from? I hope you are not just making assumptions here. Boost mpl uses techniques such as lazy template instantiation to try and reduce compile-times instead of exploding like naive template meta-programming does.
If you want to avoid manual type recursion, std::common_type appears to me to be the only utility in the STL which is a variadic template, and hence the only one which could potentially encapsulate recursion.
Solution 1
std::common_type finds the least-derived type in a set of types. If we identify numbers with types, specifically high numbers with less-derived types, it finds the greatest number in a set. Then, we have to map equality to the key type onto a level of derivation.
using namespace std;
struct base_one { enum { value = 1 }; };
struct derived_zero : base_one { enum { value = 0 }; };
template< typename A, typename B >
struct type_equal {
typedef derived_zero type;
};
template< typename A >
struct type_equal< A, A > {
typedef base_one type;
};
template< typename Key, typename ... Types >
struct pack_any {
enum { value =
common_type< typename type_equal< Key, Types >::type ... >::type::value };
};
Solution 2
We can hack common_type a little more. The standard says
A program may specialize this trait if
at least one template parameter in the
specialization is a user-defined type.
and describes exactly what is inside it: a recursive partial specialization case, a case which applies a binary operator, and a terminal case. Essentially, it's a generic fold function, and you can add whatever binary operation you please. Here I used addition because it's more informative than OR. Note that is_same returns an integral_constant.
template< typename Addend >
struct type_sum { // need to define a dummy type to turn common_type into a sum
typedef Addend type;
};
namespace std { // allowed to specialize this particular template
template< typename LHS, typename RHS >
struct common_type< type_sum< LHS >, type_sum< RHS > > {
typedef type_sum< integral_constant< int,
LHS::type::value + RHS::type::value > > type; // <= addition here
};
}
template< typename Key, typename ... Types >
struct pack_count : integral_constant< int,
common_type< type_sum< is_same< Key, Types > > ... >::type::type::value > {};