Function template, disallowing certain types - c++

I have a function template that must be allow only certain types. I've seen other questions but they used boost and primitve types. In this case, no boost, and it's a user defined class.
Ex:
template<typename T>
myfunc(T&)
{ ... }
template<>
myfunc(Foo&)
{
static_assert(false, "You cannot use myfunc with Foo");
}
Problem is static_assert gets called regardless of whether I call myfunc with a Foo object or not.
I just want some way for compile to stop when myfunc is called with Foo.
How can I achieve this functionality?

You can use std::is_same for this:
#include <type_traits>
template<typename T>
return_type myfunc(T&)
{
static_assert(std::is_same<T, Foo>::value, "You cannot use myfunc with Foo");
// ...
}

With a return type R, say:
#include <type_traits>
template <typename T>
typename std::enable_if<!std::is_same<T, Foo>::value, R>::type my_func(T &)
{
// ...
}
If you really don't want to use the standard library, you can write the traits yourself:
template <bool, typename> struct enable_if { };
template <typename T> struct enable_if<true, T> { typedef T type; };
template <typename, typename> struct is_same { static const bool value = false; };
template <typename T> struct is_same<T, T> { static const bool value = true; };

Related

c++ templates overloading method depend on class type

I have class like this:
template<typename T>
MyClass{
//myFunc();
}
I want to create myFunc method that return numeric value if class template is numeric and return nothing (void) when class template is not numeric.
For now, I got sth like this:
template<typename T>
MyClass{
template <typename returnT>
returnT myFunc();
}
template <typename T>
template <typename returnT>
typename std::enable_if<std::is_arithmetic<T>::value>
T MyClass<T>::myFunc()
{
return T::value;
}
template <typename T>
template <typename returnT>
typename std::enable_if<!std::is_arithmetic<T>::value>
void MyClass::myFunc()
{
//do sth
}
of course, that doesn't work. Is that a good idea to solve this problem this way? What is "smart" and working solution?
As an alternative to the constexpr if solution already supplied, here is your initial idea in it's working form.
#include <type_traits>
#include <iostream>
template<typename T>
struct MyClass{
template <typename returnT = T, std::enable_if_t<std::is_arithmetic_v<returnT>, bool> = true>
T myFunc();
template <typename returnT = T, std::enable_if_t<!std::is_arithmetic_v<returnT>, bool> = true>
void myFunc();
};
template <typename T>
template <typename returnT, std::enable_if_t<std::is_arithmetic_v<returnT>, bool>>
T MyClass<T>::myFunc()
{
std::cout << "yo\n";
return T{};
}
template <typename T>
template <typename returnT, std::enable_if_t<!std::is_arithmetic_v<returnT>, bool>>
void MyClass<T>::myFunc()
{
std::cout << "yay\n";
}
int main() {
MyClass<int> m;
MyClass<std::string> n;
m.myFunc();
n.myFunc();
}
The simplest way I can think of would be to just use if constexpr:
template <typename T>
class MyClass
{
auto myFunc()
{
if constexpr (std::is_arithmetic_v<T>)
{
return T{};
}
else
{
// do smth
}
}
};
If you can't use C++17, you will have to revert to some SFINAE-based approach. What that would best look like exactly depends a lot on what the actual signatures involved should be. But, for example, you could provide a partial class template specialization for the case of an arithmetic type:
template <typename T, typename = void>
class MyClass
{
void myFunc()
{
// do smth
}
};
template <typename T>
class MyClass<T, std::enable_if_t<std::is_arithmetic<T>::value>>
{
T myFunc()
{
return {};
}
};
Note that an arithmetic type cannot be a class type or enum, so I'm not sure what T::value was trying to achieve in your example code for the case of T being an arithmetic type…
I would create a helper template class to select the return type, and a helper function that uses overloading to perform the right behavior.
template <typename, bool> struct RType;
template <typename T> struct RType<T, false> { typedef void type; };
template <typename T> struct RType<T, true> { typedef T type; };
template<typename T>
class MyClass{
typedef RType<T, std::is_arithmetic<T>::value> R;
void myFuncT(RType<T, false>) {}
T myFuncT(RType<T, true>) { return 0; }
public:
typename R::type myFunc() { return myFuncT(R()); }
};

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

Testing if member function exists using variadics

So I'm very familiar with the paradigm of testing if a member function exists. Currently this code works:
#include <iostream>
#include <type_traits>
struct has_mem_func_foo_impl {
template <typename U, U>
struct chk { };
template <typename Class, typename Arg>
static std::true_type has_foo(chk<void(Class::*)(Arg), &Class::foo>*);
template <typename, typename>
static std::false_type has_foo(...);
};
template <typename Class, typename Arg>
struct has_mem_func_foo : decltype(has_mem_func_foo_impl::template has_foo<Class,Arg>(nullptr)) { };
struct bar {
void foo(int) { }
};
int main() {
static_assert( has_mem_func_foo<bar, int>::value, "bar has foo(int)" );
}
unfortunately if I make a slight adjustment:
#include <iostream>
#include <type_traits>
struct has_mem_func_foo_impl {
template <typename U, U>
struct chk { };
template <typename Class, typename... Arg>
static std::true_type has_foo(chk<void(Class::*)(Arg...), &Class::foo>*);
template <typename, typename...>
static std::false_type has_foo(...);
};
template <typename Class, typename... Arg>
struct has_mem_func_foo : decltype(has_mem_func_foo_impl::template has_foo<Class,Arg...>(nullptr)) { };
struct bar {
void foo(int) { }
};
int main() {
static_assert( has_mem_func_foo<bar, int>::value, "bar has foo(int)" );
}
my static assertion fails. I was under the impression that variadic template parameter packs are treated just the same when expanded into their places. Both gcc and clang produce a failed static assertion.
The real root of my question is thus, is this standard behavior? It also fails when testing for the presence of a variadic templated member function.
The problem I see is that Arg... being passed int is not enough. It would be valid for the compiler to add new args to the end of it.
Deducing what to add to the end of it from nullptr_t isn't possible, so the compiler says "I give up, not this case".
But we don't need to have Arg... in a deducable context for your trick to work:
#include <iostream>
#include <type_traits>
template<class Sig>
struct has_mem_func_foo_impl;
template<class R, class...Args>
struct has_mem_func_foo_impl<R(Args...)> {
template <typename U, U>
struct chk { };
template <typename Class>
static constexpr std::true_type has_foo(chk<R(Class::*)(Args...), &Class::foo>*) { return {}; }
template <typename>
static constexpr std::false_type has_foo(...) { return {}; }
};
template <typename Class, typename Sig>
struct has_mem_func_foo :
decltype(has_mem_func_foo_impl<Sig>::template has_foo<Class>(nullptr))
{};
struct bar {
void foo(int) { }
};
int main() {
static_assert( has_mem_func_foo<bar, void(int)>::value, "bar has foo(int)" );
}
we move the Args... to the class itself, then only pass in the type to the function. This blocks deduction, which makes nullptr conversion to the member function pointer doable, and things work again.
I also included some improved signature based syntax, which also means it supports return type matching.
Note that you may be asking the wrong question. You are asking if there is a member function with a particular signature: often what you want to know is if there is a member function that is invokable with a certain set of arguments, with a return type compatible with your return value.
namespace details {
template<class T, class Sig, class=void>
struct has_foo:std::false_type{};
template<class T, class R, class... Args>
struct has_foo<T, R(Args...),
typename std::enable_if<
std::is_convertible<
decltype(std::declval<T>().foo(std::declval<Args>()...)),
R
>::value
|| std::is_same<R, void>::value // all return types are compatible with void
// and, due to SFINAE, we can invoke T.foo(Args...) (otherwise previous clause fails)
>::type
>:std::true_type{};
}
template<class T, class Sig>
using has_foo = std::integral_constant<bool, details::has_foo<T, Sig>::value>;
which tries to invoke T.foo(int), and checks if the return value is compatible.
For fun, I made the type of has_foo actually be true_type or false_type, not inherited-from. I could just have:
template<class T, class Sig>
using has_foo = details::has_foo<T, Sig>;
if I didn't want that extra feature.

Function templates: Different specializations with type traits

Considering class templates, it is possible to provide template specializations for certain types of groups using type traits and dummy enabler template parameters. I've already asked that earlier.
Now, I need the same thing for function templates: I.e., I have a template function and want a specialization for a group of types, for example, all types that are a subtype of a class X. I can express this with type traits like this:
std::enable_if<std::is_base_of<X, T>::value>::type
I thought about doing it this way:
template <typename T, typename ENABLE = void>
void foo(){
//Do something
}
template <typename T>
void foo<T,std::enable_if<std::is_base_of<A, T>::value>::type>(){
//Do something different
}
However, this does not work since partial specialization is not allowed for function templates. So how to do it then? Maybe a default parameter with the type trait as type? But how does the code look like then?
Overloads:
void foo_impl(T, std::false_type);
void foo_impl(T, std::true_type);
foo(T t) { foo_impl(t, std::is_base_of<A, T>()); }
The closest to what you're asking is enable_if on the return type:
template<typename T> typename std::enable_if<std::is_same<T, int>::value>::type foo();
template<typename T> typename std::enable_if<std::is_same<T, char>::value>::type foo();
However, dispatching to a helper function or class is likely to be more readable and efficient.
Helper function:
template<typename T> void foo_helper(std::true_type);
template<typename T> void foo_helper(std::false_type);
template<typename T> void foo() { foo_helper(std::is_same<T, int>()); }
Helper class:
template<typename T, bool = std::is_same<T, int>::value> struct foo_helper {};
template<typename T> struct foo_helper<T, true> { static void foo(); };
template<typename T> struct foo_helper<T, false> { static void foo(); };
template<typename T> void foo() { foo_helper<T>::foo(); }
Do the actual implementation (partial specializations etc..) in class templates and write a small wrapper template function that does nothing but call a static function in your class templates.
Tried a few things and finally came up with the correct syntax myself - sorry for asking. I didn't know that enable_if has a second parameter. By using this parameter and a default value, it is possible.
Here is the answer
template<typename T>
void foo(typename std::enable_if<std::is_base_of<A, T>::value,int>::type ENABLER = 0){
std::cout << "T is a subclass of A!";
}
template<typename T>
void foo(typename std::enable_if<!std::is_base_of<A, T>::value,int>::type ENABLER = 0){
std::cout << "T is NOT a subclass of A";
}

detecting typedef at compile time (template metaprogramming)

I am currently doing some template metaprogramming. In my case I can handle any "iteratable" type, i.e. any type for which a typedef foo const_iterator exists in the same manner. I was trying to use the new C++11 template metaprogramming for this, however I could not find a method to detect if a certain type is missing.
Because I also need to turn on/off other template specializations based on other characteristics, I am currently using a template with two parameters, and the second one gets produced via std::enable_if. Here is what I am currently doing:
template <typename T, typename Enable = void>
struct Foo{}; // default case is invalid
template <typename T>
struct Foo< T, typename std::enable_if<std::is_fundamental<T>::value>::type>{
void do_stuff(){ ... }
};
template<typename T>
struct exists{
static const bool value = true;
};
template<typename T>
struct Foo<T, typename std::enable_if<exists< typename T::const_iterator >::value >::type> {
void do_stuff(){ ... }
};
I was not able to do something like this without the exists helper template. For example simply doing
template<typename T>
struct Foo<T, typename T::const_iterator> {
void do_stuff(){ ... }
};
did not work, because in those cases where this specialization should be used, the invalid default case was instantiated instead.
However I could not find this exists anywhere in the new C++11 standard, which as far as I know simply is taking from boost::type_traits for this kind of stuff. However on the homepage for boost::type_traits does not show any reference to anything that could be used instead.
Is this functionality missing, or did I overlook some other obvious way to achieve the desired behavior?
If you simply want if a given type contains const_iterator then following is a simplified version of your code:
template<typename T>
struct void_ { typedef void type; };
template<typename T, typename = void>
struct Foo {};
template<typename T>
struct Foo <T, typename void_<typename T::const_iterator>::type> {
void do_stuff(){ ... }
};
See this answer for some explanation of how this technique works.
You can create a trait has_const_iterator that provides a boolean value and use that in the specialization.
Something like this might do it:
template <typename T>
struct has_const_iterator {
private:
template <typename T1>
static typename T1::const_iterator test(int);
template <typename>
static void test(...);
public:
enum { value = !std::is_void<decltype(test<T>(0))>::value };
};
And then you can specialize like this:
template <typename T,
bool IsFundamental = std::is_fundamental<T>::value,
bool HasConstIterator = has_const_iterator<T>::value>
struct Foo; // default case is invalid, so no definition!
template <typename T>
struct Foo< T, true, false>{
void do_stuff(){// bla }
};
template<typename T>
struct Foo<T, false, true> {
void do_stuff(){//bla}
};
Here's another version of a member type trait check:
template<typename T>
struct has_const_iterator
{
private:
typedef char yes;
typedef struct { char array[2]; } no;
template<typename C> static yes test(typename C::const_iterator*);
template<typename C> static no test(...);
public:
static const bool value = sizeof(test<T>(0)) == sizeof(yes);
};
There is a couple of ways to do this. In C++03, you could use boost and enable_if to define the trait (docs, source):
BOOST_MPL_HAS_XXX_TRAIT_DEF(const_iterator);
template <typename T, typename Enable = void>
struct Foo;
template <typename T>
struct Foo< T, typename boost::enable_if<boost::is_fundamental<T> >::type>{
void do_stuff(){ ... }
};
template<typename T>
struct Foo<T, typename boost::enable_if<has_const_iterator<T> >::type> {
void do_stuff(){ ... }
};
In C++11, you could use Tick like this:
TICK_TRAIT(has_const_iterator)
{
template<class T>
auto require(const T&) -> valid<
has_type<typename T::const_iterator>
>;
};
template <typename T, typename Enable = void>
struct Foo;
template <typename T>
struct Foo< T, TICK_CLASS_REQUIRES(std::is_fundamental<T>::value)>{
void do_stuff(){ ... }
};
template<typename T>
struct Foo<T, TICK_CLASS_REQUIRES(has_const_iterator<T>())> {
void do_stuff(){ ... }
};
Also with Tick you can further enhance the trait to actually detect that the const_iterator is actually an iterator, as well. So say we define a simple is_iterator trait like this:
TICK_TRAIT(is_iterator,
std::is_copy_constructible<_>)
{
template<class I>
auto require(I&& i) -> valid<
decltype(*i),
decltype(++i)
>;
};
We can then define has_const_iterator trait to check that the const_iterator type matches the is_iterator trait like this:
TICK_TRAIT(has_const_iterator)
{
template<class T>
auto require(const T&) -> valid<
has_type<typename T::const_iterator, is_iterator<_>>
>;
};