How to restrict typenames in template - c++

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

Related

Macro for (SFINAEd) template function

#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).

Is it possible to make a template that can only take specific types?

I was wondering if it was possible for a template (or any other tool you might recommend)to only take a type from a list of specific types (like an enum, but with already existing types).
More specifically, if I have 3 classes, class A, class B and class C, and I'd like a function to be able to take any of those three classes as argument (but no other class than the 3), what should I do ?
Should I use a template (if so how should I use it), or are there other tools for me to use ?
The options that comes to mind for me are SFINAE, static_assert or overloading. What option is best would depend on the function itself.
SFINAE method
#include <type_traits>
template <typename T, typename std::enable_if<
std::is_same<A, T>::value ||
std::is_same<B, T>::value ||
std::is_same<C, T>::value, int>::type = 0>
void foo(T t) {
// ...
}
Static assert
template <typename T>
void foo(T t) {
static_assert(std::is_same<A, T>::value ||
std::is_same<A, T>::value ||
std::is_same<A, T>::value, "Must pass A, B or C");
// ...
}
Overloading
void foo(A a) {
// ...
}
void foo(B a) {
// ...
}
void foo(C a) {
// ...
}
Why do you only want this to work for three classes? In general, it's a better idea to keep your interfaces open and support any types that come along (within reason, of course).
If you're sure you want to do this, then a custom type trait and enable_if is probably the best route.
#include <iostream>
#include <type_traits>
template <typename T>
struct is_my_special_type;
template <>
struct is_my_special_type<int> {
static const bool value = true;
};
template <>
struct is_my_special_type<long> {
static const bool value = true;
};
template <typename T, typename std::enable_if<is_my_special_type<T>::value, int>::type = 0>
void foo(T val) {
std::cout << val << '\n';
}
int main() {
foo(10);
foo(10l);
foo(10.0); // won't compile unless you comment this line out
return 0;
}
You can add types through template specialization of my_special_type. You could also use static_assert instead of enable_if if you wanted.
Constraining template parameters to only be of specific types, or types meeting certain requirements, is part of what C++ Concepts is about.
Concepts are a future feature of the C++ language (coming to the official standard perhaps in C++20), which have been specified in a TS (technical specification) - making them a possible extension for compilers to implement if they wish.
For a short introduction-that's-not-intended-as-such, watch:
What makes a good C++ concept? / Bjarne Stroustrup, CppCon 2016

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!

Using non-type template argument during partial specialization

Consider the following structs:
//Implementations provided elsewhere
struct A { A(int i, double d, std::string s); /* ... */ };
struct B { B(double d1, double d2); /* ... */ };
I have two conversion classes whose template signatures look like:
TupleAs< A, int, double, std::string > via1 { ... };
ArrayAs< B, double, 2 > via2 { ... };
Predictably, TupleAs converts a triplet of int,double, and std::string values into an object of type A. Similarly, ArrayAs converts a pair of two double values into an object of type B. (And yes, there are reasons why I cannot call the A and B constructors directly.)
Improving the syntax
I would like to change the syntax so I can do the following:
TupleAs< A(int,double,std::string) > via1 { ... };
ArrayAs< B(double,2) > via2 { ... };
which, I think, is more descriptive of a conversion process. The TupleAs template declaration and corresponding partial specialization would look like this:
template <typename T> struct TupleAs;
template <typename T, typename ... Args>
struct TupleAs<T(Args...)> { ... };
Compiler errors
However, if I try to do something similar with the ArrayAs version:
template <typename T> struct ArrayAs;
template <typename T, typename U, unsigned N>
struct ArrayAs<T(U,N)> { ... };
I get the following errors in clang (3.6) when trying to instantiate it (ArrayAs< B(double,2)> test;):
typeAs.cpp:14:22: error: unknown type name 'N'
struct ArrayAs<T(U,N)>{
^
typeAs.cpp:14:10: warning: class template partial specialization contains a template parameter that cannot be deduced; this partial specialization will never be used
struct ArrayAs<T(U,N)>{
^~~~~~~~~~~~~~~
typeAs.cpp:13:45: note: non-deducible template parameter 'N'
template<typename T, typename U, unsigned N>
^
The gcc error diagnostic is a little different, but I won't post it here.
I admit that my templating skills should be better than they are, and I also concede that an analogous std::function<B(double,2)> declaration clearly is nonsense. But can someone tell me why the particular syntax I'm trying to achieve is not allowed? I looked through the C++14 standard and had trouble finding the relevant portion, and I'm having trouble interpreting the clang diagnostic message.
When you specialize TupleAs:
template <typename T, typename ... Args>
struct TupleAs<T(Args...)>
You are basically overloading the notation for a function. You are specializing on a function that takes Args... and returns a T. That is a type. You may not be using that function as a function, or really ever think about it as being a type, but that is what it is.
On the other hand, here:
template <typename T, typename U, unsigned N>
struct ArrayAs<T(U,N)> { ... };
There is no such thing as a function that takes N. It could take unsigned, but it can't take a value. There is just no such reasonable thing. From your example, B(double, 2) simply does not make sense. At best, you could write something that would allow:
template <unsigned N> using size_ = std::integral_constant<size_t, N>;
ArrayAs< B(double,size_<2>) >
Or even:
ArrayAs< B(std::array<double, 2>) >
since now we're back to using types everywhere. Whether you prefer that or not is personal preference.
The key here is that types are first-class citizens when it comes to all things template metaprogramming, and values should be avoided where possible.
template <typename T> struct ArrayAs;
template <typename T, typename U, std::size_t N>
struct ArrayAs<T(std::array<U,N>)> { ... };
works, as would:
template<class T>
struct to_array;
template<class T, size_t N>
struct to_array< T[N] > { using type = std::array<T, N>; };
template<class T>
using arr = typename to_array<T>::type;
then:
ArrayAs< Bob( arr<int[3]> ) > some_var;
live example.
Sadly, directly using ArrayAs< Bob( int[3] ) > doesn't work due to how arrays in function types decay to pointers.

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 > {};