I'm starting to learn about traits and templates in c++. What I'm wondering is is it possible to create templates for signed/unsigned integral types. The idea is that the normal class would (probably) be implemented for singed integer types, and the variation for unsigned integer types. I tried:
template <typename T>
class FXP<T>
{ ... };
template <typename T>
class FXP<unsigned T>
{ ... };
but this does not compile.
I even came across:
std::is_integral
std::is_signed
std::is_unsigned
So, how do I put these in action to define a class that only supports these two variants?
In this case, there's a few ways to go about it, but my favorite for cases where there's a limited number of variants (e.g., a boolean or two saying which way it should behave), partial specialization of a template is usually the best way to go:
// Original implementation with default boolean for the variation type
template <typename T, bool is_unsigned = std::is_unsigned<T>::value>
class FXP {
// default implementation here
};
Your next step is to then provide a partial specialization that takes the typename T, but only works for a specific variant of the template parameters (e.g. true or false).
template <typename T>
class FXP<T, false> {
// partial specialization when is_unsigned becomes false
};
template <typename T>
class FXP<T, true> {
// partial specialization when is_unsigned becomes true
};
In this case, if you write a default implementation, you only need to make a specialization for the case that's non-default (like the true case).
Here's an example, where the default case gets overridden by a specialized template parameter:
http://coliru.stacked-crooked.com/a/bc761b7b44b0d452
Note that this is better only for smaller cases. If you need complex tests, you're better off using std::enable_if and some more complicated template parameters (like in DyP's answer).
Good luck!
With an additional template parameter:
#include <iostream>
#include <type_traits>
template <typename T, class X = void>
struct FXP
{
// possibly disallow using this primary template:
// static_assert(not std::is_same<X, X>{},
// "Error: type neither signed nor unsigned");
void print() { std::cout << "non-specialized\n"; }
};
template <typename T>
struct FXP< T, typename std::enable_if<std::is_signed<T>{}>::type >
{ void print() { std::cout << "signed\n"; } };
template <typename T>
struct FXP< T, typename std::enable_if<std::is_unsigned<T>{}>::type >
{ void print() { std::cout << "unsigned\n"; } };
struct foo {};
int main()
{
FXP<foo>().print();
FXP<int>().print();
FXP<unsigned int>().print();
}
Related
I aim to implement a structure template that can be used to detect either if a template substitution is well formed or will fail. An example of usage is to provide two versions of template functions depending on whether the template parameter is comparable or not.
It can be solved quite easily if one provides structures for each scenario explicitly, e.g. whether there exists an equality operator for the template type, as shown here. But I failed to implement a structure that would accept (almost) arbitrary construct as a template argument.
The "best" approach I have reached so far uses template template argument. It compiles, but it does not fit the case when the argument substitution should be well formed.
#include <iostream>
#include <type_traits>
template <typename T = void, typename...>
using Enable = T;
template <bool Cond, typename T = void>
using Enable_if = typename std::enable_if<Cond, T>::type;
template <typename T, template<typename> class X, typename = void>
struct Is_enabled : std::false_type {};
template <typename T, template<typename> class X>
struct Is_enabled<T, X, Enable<X<T>>> : std::true_type {};
/// An example of construct
template <typename T>
using Equals = decltype(std::declval<T>() == std::declval<T>());
template <typename T>
using Enabled_eq = Enable_if<Is_enabled<T, Equals>::value>;
template <typename T>
using Disabled_eq = Enable_if<!Is_enabled<T, Equals>::value>;
template <typename T>
Enabled_eq<T> foo()
{
std::cerr << "enabled!" << std::endl;
}
template <typename T>
Disabled_eq<T> foo()
{
std::cerr << "disabled!" << std::endl;
}
struct A {};
int main(int /*argc*/, const char* /*argv*/[])
{
foo<int>(); /// should print "enabled!"
foo<A>(); /// should print "disabled!"
return 0;
}
In case of int, it should obviously print "enabled!", and in case of A it should print "disabled!". But it always prints "disabled!", so the specialization of Is_enabled is never done.
Am I somewhat close to a correct solution, or will it be more complicated?
The third template parameter of Is_enabled defaults to void. This is what the compiler will use in the Is_enabled<T, Equals> instantiation. That is, Is_enabled<T, X, Enable<X<T>>> : std::true_type {}; can be used only if Enable<X<T>> evaluates to void. By explicitly passing a template argument X<T> to class template Enable declared as:
template <typename T = void, typename...>
using Enable = T;
you actually create an alias for X<T> itself, and the void type (the default one, needed for the dispatching to work) is not used at all. In your case, X<T> is the result of the decltype specifier. For foo<A>() it does lead to instantiation failure. For foo<int>(), however, you get the result type of integers comparison which is bool. That is, although there is no subsitution failure, the compiler cannot use the class template specialization, because it is specialized for void, not bool.
In order to fix the code, you should rewrite Enable to always result with void:
template <typename...>
using Enable = void;
This is also known as std::void_t.
With C++20 and concepts around the corner I wondered if it will be possible to write a concept to check if a Type has a function with a certain name which takes any number of arbitrary arguments.
Take the following code for example (with GCC's current concept TS syntax):
template <typename T>
concept bool Initializable = requires(T t) {
{ t.init() } ->void;
};
struct S {
void init() {}
};
static_assert(Initializable<S>);
The concept Initializable checks if a Type implements a void init() function. Now lets assume there is another Type which also has an init function but one which requires arguments, e.g. an int:
struct T {
void init(int) {}
};
Now in this case the static assertion would fail.
Is there any way to make the Initializable concept ignore the function arguments? This example might seem rather derived, but for something like a generic serializer there might be use-cases for such a concept.
There is a type trait for that, std::is_member_function_pointer. But if you want that the return type is void too, then you can do both at the same time:
template <typename>
struct mptr_returns_void : std::false_type {};
template <typename T, typename ...Args>
struct mptr_returns_void<void(T::*)(Args...)> : std::true_type {};
template <typename T>
concept Initializable = mptr_returns_void<decltype(&T::init)>::value;
I would like to find out if a type defines a member function with a template argument but the template argument is constrained with SFINAE.
Example I have a type A with a single function foo
struct A{
template<typename T>
std::enable_if<Condition<T>,ReturnType> foo(T t){ ... }
};
Condition is some condition e.g. std::is_pos_v
Right now I'm using boost::hana::is_valid to figure out if a type has a member function like foo() or foo(int) but when with template argument I'm lost.
I would like to write something like this
auto has_foo = hana::is_valid([](auto t) -> delctype(hana::traits::declval(t).foo(???)){});
has_foo(hana::type_c<A>); // <-- I want this to return true
The question is what should I put instead of ??? ?
It is probably impossible for the compiler to "prove" that a type A satisfy: "For every type T which satisfy Condition there is a member function A::foo(T)"
So to make it easier for the compiler, I would be happy to at least "prove" that for a type A holds: "There is a type T such that there is a member function A::foo(T)"
Unfortunately, this is still hard in my example because this would require proving that there is a type which satisfy Condition.
Thus isn't it possible for the purpose of introspection to ignore SFIANE? Then I could pick an arbitrary type and test existence of e.g. A::foo(int).
As stated, there is no facility provided for this kind of introspection short of writing a compiler plugin and walking the AST yourself.
You can certainly use hana::is_valid if you provide a concrete T to make a complete and valid expression.
I provided an additional example that allows providing a "concept" assuming some kind of facility for providing a concrete T for whatever "concept" you put in. This is a bit of a reach though.
#include <boost/hana.hpp>
#include <type_traits>
#include <utility>
namespace hana = boost::hana;
using hana::Sequence;
struct A {
template <typename T>
std::enable_if_t<Sequence<T>::value, void> foo(T) { }
};
struct B {
template <typename T>
void bar(T) { }
};
template <typename T>
auto has_foo_1 = hana::is_valid([](auto&& a)
-> decltype(std::forward<decltype(a)>(a).foo(std::declval<T>())) { });
template <template <typename, typename> typename Concept>
auto declval_concept_impl = int{};
template <>
auto declval_concept_impl<Sequence> = hana::tuple<>{};
template <template <typename, typename> typename Concept>
using declval_concept = std::add_rvalue_reference_t<decltype(declval_concept_impl<Concept>)>;
template <template <typename, typename> typename Concept>
auto has_foo_2 = hana::is_valid([](auto&& a)
-> decltype(std::forward<decltype(a)>(a).foo(declval_concept<Concept>{})) { });
int main() {
A a;
B b;
static_assert( has_foo_1<hana::tuple<>>(a));
static_assert(not has_foo_1<hana::tuple<>>(b));
static_assert( has_foo_2<Sequence>(a));
static_assert(not has_foo_2<Sequence>(b));
}
I have the following class structure
// file foo.h:
struct foo_base
{ ... }
template<typename T> struct foo : foo_base
{ ... };
template<typename F>
using is_foo = std::is_convertible<F,foo_base>;
template<typename, typename=void> struct aux;
template<typename Foo>
struct aux<Foo, typename std::enable_if<is_foo<Foo>::value>::type>
{ ... }; // specialisation for any foo
// file bar.h:
#include "foo.h"
template<typename T> struct bar : foo<T>
{ ... };
template<typename T>
struct aux<bar<T>>
{ ... }; // specialisation for bar<T>
Now, the problem is that for aux<bar<T>> both specialisations provided for aux are viable. Is there a way to avoid this disambiguity without providing another specialisation for every T? Note that modifications to file foo.h must not know about file bar.h.
Note The ambiguity shall be resolved such that the specialisation provided in file bar.h is picked for any aux<bar<T>>. Originally, bar was not a template and the specialisation aux<bar> not partial and hence preferred. The problem arose by making bar a template.
The compiler doesn't see struct aux<bar<T>> as more specialised than struct aux<Foo, typename std::enable_if<is_foo<Foo>::value>::type> because of second template argument. You can specify the second argument the same way in your bar<T> specialisation:
template<typename T>
struct aux<bar<T>, typename std::enable_if<is_foo<bar<T>>::value>::type>
{ };
The rules for how specialised partial template specialisations are are complicated, but I will try to explain very briefly:
The three (your two, plus my one) relevant specialisations are
template<typename Foo>
struct aux<Foo, typename std::enable_if<is_foo<Foo>::value>::type>
template<typename T>
struct aux<bar<T>> // or aux<bar<T>, void>
{ };
template<typename T>
struct aux<bar<T>, typename std::enable_if<is_foo<bar<T>>::value>::type>
{ };
Per the standard (14.5.5.2), to determine which of the class template partial specialisations is the most specialised, the question that needs to be answered is which of the following function template overloads would be the best match in a call to f(aux<bar<T>>()):
template<typename Foo>
void f(aux<Foo, typename std::enable_if<is_foo<Foo>::value>::type>); // 1
template<typename T>
void f(aux<bar<T>>); // or aux<bar<T>, void> // 2
template<typename T>
void f(aux<bar<T>, typename std::enable_if<is_foo<bar<T>>::value>::type>); // 3
And there, in turn, the partial ordering rules for functions say that 1 is not more specialised than 2, and that 2 is not more specialised than 1, roughly speaking, because 1 is not clearly more specialised than 2, and 2 is not clearly more specialised than 1. "Clearly more specialised" is not how the standard words it, but that essentially means that based on the type arguments of one of those, the type arguments of the other are not deducible.
When comparing 1 and 3, however, the arguments of 1 are deducible from 3: Foo can be deduced as bar<T>. Therefore, 3 is at least as specialised as 1. However, the arguments of 3 are not deducible from 1: T cannot be deduced at all. The compiler's conclusion therefore is that 3 is more specialised than 1.
Partial specialization of class templates is based on pattern matching. In contrast, customizing function templates is based on template argument deduction and overload resolution.
Because of the class hierarchy present in your problem, customizing behavior would in principle be more convenient through function template overloading, because that can take derived-to-base conversions into account. The pattern matching used in partial class template specialization does not provide the same flexibility.
However, since C++11, it is possible to do compile-time return type deduction. Here is a solution that combines tag dispatching, default constructors and decltype type deduction:
#include <iostream>
// file foo_base.h:
struct foo_base
{
foo_base() = default;
};
foo_base faux(foo_base const&)
{
return foo_base{};
}
template<class T, class = decltype(faux(T{}))>
struct aux;
template<class T>
struct aux<T, foo_base>
{
enum { value = 1 };
};
// file foo.h:
template<typename T>
struct foo : foo_base
{
foo() = default;
};
// file bar.h:
template<typename T>
struct bar : foo<T>
{
bar() = default;
};
template<class T>
bar<T> faux(bar<T> const&)
{
return bar<T>{};
}
template<class T, class U>
struct aux<T, bar<U>>
{
enum { value = 2 };
};
// file meow.h
template<class T>
struct meow : bar<T>
{
meow() = default;
};
int main()
{
std::cout << aux<foo_base>::value; // 1
std::cout << aux<foo<int>>::value; // 1
std::cout << aux<bar<int>>::value; // 2
std::cout << aux<meow<int>>::value; // 2
}
Live Example that works with both g++ and clang in C++11 mode (C++14 mode is not required!).
The constexpr function faux() is overloaded for foo_bar and as a function template for bar<T>. Any argument whose class is derived from foo_base but not from bar<T> will select the former overload, and anything derived from bar<T> will select the latter overload. This mechanism is the same as e.g. in the Standard Library where iterator categories are used to tag dispatch several implementations of std::advance() e.g.
To use this selection mechanism during partial specialization of your class template aux, two more ingredients are required. First, all classes are required to have a default constructor. Secondly, decltype() is applied to that expression faux(T{}) to deduce the return type.
NOTE: it is not required that faux() is constexpr or that any of the default constructors are constexpr, because decltype() will
not actually evaluate the function call but only deduce its return
type.
The main class template aux has a default template argument:
template<class T, class = decltype(faux(T{}))>
struct aux;
Partially specializing the second argument on foo_base allows you to provide behavior for any class that derives from foo_base:
template<class T>
struct aux<T, foo_base>
{ // custom behavior for anything derived from foo_bar };
The second partial specialization matches any class derived from any template instantiation bar<U>
template<class T, class U>
struct aux<T, bar<U>>
{ // custom behavior for anything derived from bar<U> for some U }
NOTE: the main drawback is that you might need to provide a default constructor to all classes in your hierarchy. This may or may not be an obstacle that you can overcome. Most classes already have a default constructor, but some may not. In that sense this solution is intrusive (i.e. it cannot be bolted on top of existing code, but it requires modification of that code).
I have an SFINAE problem:
In the following code, I want the C++ compiler to pick the specialized functor and print "special", but it's printing "general" instead.
#include <iostream>
#include <vector>
template<class T, class V = void>
struct Functor {
void operator()() const {
std::cerr << "general" << std::endl;
}
};
template<class T>
struct Functor<T, typename T::Vec> {
void operator()() const {
std::cerr << "special" << std::endl;
}
};
struct Foo {
typedef std::vector<int> Vec;
};
int main() {
Functor<Foo> ac;
ac();
}
How can I fix it so that the specialized struct is used automatically? Note I don't want to directly specialize the Functor struct on Foo, but I want to specialize it on all types that have a Vec type.
P.S.: I am using g++ 4.4.4
Sorry for misleading you in the last answer, I thought for a moment that it would be simpler. So I will try to provide a complete solution here. The general approach to solve this type of problems is to write a traits helper template and use it together with enable_if (either C++11, boost or manual implementation) to decide a class specialization:
Trait
A simple approach, not necessarily the best, but simple to write would be:
template <typename T>
struct has_nested_Vec {
typedef char yes;
typedef char (&no)[2];
template <typename U>
static yes test( typename U::Vec* p );
template <typename U>
static no test( ... );
static const bool value = sizeof( test<T>(0) ) == sizeof(yes);
};
The approach is simple, provide two template functions, that return types of different sizes. One of which takes the nested Vec type and the other takes ellipsis. For all those types that have a nested Vec the first overload is a better match (ellipsis is the worst match for any type). For those types that don't have a nested Vec SFINAE will discard that overload and the only option left will be the ellipsis. So now we have a trait to ask whether any type has a nested Vec type.
Enable if
You can use this from any library, or you can roll your own, it is quite simple:
template <bool state, typename T = void>
struct enable_if {};
template <typename T>
struct enable_if<true,T> {
typedef T type;
};
When the first argument is false, the base template is the only option, and that does not have a nested type, if the condition is true, then enable_if has a nested type that we can use with SFINAE.
Implementation
Now we need to provide the template and the specialization that will use SFINAE for only those types with a nested Vec:
template<class T, class V = void>
struct Functor {
void operator()() const {
std::cerr << "general" << std::endl;
}
};
template<class T>
struct Functor<T, typename enable_if<has_nested_Vec<T>::value>::type > {
void operator()() const {
std::cerr << "special" << std::endl;
}
};
Whenever we instantiate Functor with a type, the compiler will try to use the specialization, which will in turn instantiate has_nested_Vec and obtain a truth value, passed to enable_if. For those types for which the value is false, enable_if does not have a nested type type, so the specialization will be discarded in SFINAE and the base template will be used.
Your particular case
In your particular case, where it seems that you don't really need to specialize the whole type but just the operator, you can mix the three elements into a single one: a Functor that dispatches to one of two internal templated functions based on the presence of Vec, removing the need for enable_if and the traits class:
template <typename T>
class Functor {
template <typename U>
void op_impl( typename U::Vec* p ) const {
std::cout << "specialized";
}
template <typename U>
void op_impl( ... ) const {
std::cout << "general";
}
public:
void operator()() const {
op_impl<T>(0);
}
};
Even though this is an old question, I think it's still worth providing a couple more alternatives for quickly fixing the original code.
Basically, the problem is not with the use of SFINAE (that part is fine, actually), but with the matching of the default parameter in the primary template (void) to the argument supplied in the partial specialization(typename T::Vec). Because of the default parameter in the primary template, Functor<Foo> actually means Functor<Foo, void>. When the compiler tries to instantiate that using the specialization, it tries to match the two arguments with the ones in the specialization and fails, as void cannot be substituted for std::vector<int>. It then falls back to instantiating using the primary template.
So, the quickest fix, which assumes all your Vecs are std::vector<int>s, is to replace the line
template<class T, class V = void>
with this
template<class T, class E = std::vector<int>>
The specialization will now be used, because the arguments will match. Simple, but too limiting. Clearly, we need to better control the type of the argument in the specialization, in order to make it match something that we can specify as the default parameter in the primary template. One quick solution that doesn't require defining new traits is this:
#include <iostream>
#include <vector>
#include <type_traits>
template<class T, class E = std::true_type>
struct Functor {
void operator()() const {
std::cerr << "general" << std::endl;
}
};
template<class T>
struct Functor<T, typename std::is_reference<typename T::Vec&>::type> {
void operator()() const {
std::cerr << "special" << std::endl;
}
};
struct Foo {
typedef std::vector<int> Vec;
};
int main() {
Functor<Foo> ac;
ac();
}
This will work for any Vec type that could make sense here, including fundamental types and arrays, for example, and references or pointers to them.
Another alternative for detecting the existence of a member type is to use void_t. As valid partial specialisations are preferable to the general implementation as long as they match the default parameter(s), we want a type that evaluates to void when valid, and is only valid when the specified member exists; this type is commonly (and, as of C++17, canonically) known as void_t.
template<class...>
using void_t = void;
If your compiler doesn't properly support it (in early C++14 compilers, unused parameters in alias templates weren't guaranteed to ensure SFINAE, breaking the above void_t), a workaround is available.
template<typename... Ts> struct make_void { typedef void type; };
template<typename... Ts> using void_t = typename make_void<Ts...>::type;
As of C++17, void_t is available in the utilities library, in type_traits.
#include <iostream>
#include <vector>
#include <type_traits> // For void_t.
template<class T, class V = void>
struct Functor {
void operator()() const {
std::cerr << "general" << std::endl;
}
};
// Use void_t here.
template<class T>
struct Functor<T, std::void_t<typename T::Vec>> {
void operator()() const {
std::cerr << "special" << std::endl;
}
};
struct Foo {
typedef std::vector<int> Vec;
};
int main() {
Functor<Foo> ac;
ac();
}
With this, the output is special, as intended.
In this case, since we're checking for the existence of a member type, the process is very simple; it can be done without expression SFINAE or the type_traits library, allowing us to rewrite the check to use C++03 facilities if necessary.
// void_t:
// Place above Functor's definition.
template<typename T> struct void_t { typedef void type; };
// ...
template<class T>
struct Functor<T, typename void_t<typename T::Vec>::type> {
void operator()() const {
std::cerr << "special" << std::endl;
}
};
To my knowledge, this should work on most, if not all, SFINAE-capable C++03-, C++11-, C++14-, or C++1z-compliant compilers. This can be useful when dealing with compilers that lag behind the standard a bit, or when compiling for platforms that don't have C++11-compatible compilers yet.
For more information on void_t, see cppreference.