Any way to check count of template parameters at compile time? - c++

Is there any way to check number of template parameters and compile time? I would like to do this (this is not real code):
template<typename... Types>
class Foo
{
// Enable this if count of 'Types' is 1.
Types[0] Bar()
{
return Types[0]{};
}
// Enable this otherwise.
std::variant<Types> Bar()
{
return std::variant<Types>{};
}
};
Is there any way to achieve this?

Not like that, at least not easily. You can probably add some helper struct that defines a type with if constexpr and sizeof...() and then use helper::return_type or seomthing.
But I think this calls for template specialization:
#include <variant>
template<typename... Types>
class Foo
{
std::variant<Types...> Bar()
{
return {};
}
};
// Specialize for just one Type
template<typename Type>
class Foo<Type>
{
Type Bar()
{
return {};
}
};

One option is to add a template parameter and then leverage constexpr if to check if the pack is empty or not like
template<typename first_t, typename... rest_t>
class Foo
{
auto Bar()
{
if constexpr (sizeof...(rest_t) == 0)
return first_t{};
else
return std::variant<first_t, rest_t...>{};
}
};

It's not too hard to create a alias template for the type by specializing a helper type:
template<class...Ts>
struct ReturnTypeHelper : std::type_identity<std::variant<Ts...>> {};
template<class T>
struct ReturnTypeHelper<T> : std::type_identity<T> {};
template<class...Ts>
using ReturnType = typename ReturnTypeHelper<Ts...>::type;
template<typename... Types>
class Foo
{
public:
auto Bar()
{
return ReturnType<Types...>{};
}
};
static_assert(std::is_same_v<decltype(std::declval<Foo<int>>().Bar()), int>);
static_assert(std::is_same_v<decltype(std::declval<Foo<int,float>>().Bar()), std::variant<int, float>>);

Related

Declare template<typename Foo<T>> instead of template<typename T>

I have a template<typename T> class Foo.
I want to declare a function that can return any kind of Foo. I would do it like this: template<typename T> Foo<T> bar();
But this means that I have to use it like this: Foo<SomeConcreteT> f = bar<SomeConcreteT>();, and SomeConcreteT can be very long and clunky and annoying to have to type out.
I do, however, have some
using AppleFoo = Foo<ABunchOfStuffForApples>;
using BananaFoo = Foo<SomethingElseForBananas>;
// ...
I would prefer to call bar like this: AppleFoo f = bar<AppleFoo>();, so I don't have to type out ABunchOfStuffForApples all the time, and conceptually, AppleFoo telly the reader more about what's supposed to happen here than ABunchOfStuffForApples does.
I can do it by adding using TType = T inside Foo and a helper function like this:
template<typename F>
F bar()
{
return bar<F::TType>();
}
But this is ugly and error-prone (e.g. calling bar<SomethingThatIsNotAFoo>()).
Is there a cleaner way of doing this?
And is there, more generally, a way of testing whether some type is a SomethingKnown<SomethingUnknown>, e.g. in a static_assert?
You can pretend to have return-type deduction, by having bar be a non-template that returns a proxy with a operator Foo<T>
template <typename T>
struct Foo {
/* ... */
};
namespace detail {
struct bar_t {
template <typename T>
operator Foo<T>() { /* current implemenation of bar */ }
};
}
detail::bar_t bar() { return {}; }
using AppleFoo = Foo<struct Apple>;
int main() {
AppleFoo f = bar();
}
You can create a traits to know if it is a Foo and extract its template parameter:
template <typename T>
struct is_foo : std::false_type {};
template <typename T>
struct is_foo<Foo<T>> : std::true_type
{
using type = T;
};
and then
template<typename FOO>
FOO bar()
{
static_assert(is_foo<FOO>::value);
using T = typename is_foo<FOO>::type;
// ...
}
As alternative, if you can change calling syntax, you might pass a tag, something along
template <typename T> struct tag {};
and then
template<typename T>
Foo<T> bar(tag<Foo<T>>)
{
return bar<T>();
}
with usage similar to
using AppleFoo = Foo<ABunchOfStuffForApples>;
auto bar1 = bar(tag<AppleFoo>{});
auto bar2 = bar(tag<Foo<ABunchOfStuffForApples>>{});
// auto is AppleFoo and so Foo<ABunchOfStuffForApples>
If you dislike tag in interface, you can still use it as implementation:
template<typename T>
Foo<T> bar_impl(tag<Foo<T>>)
{
// implementation, such as return Foo<T>();
}
// Possibly other specialization for Foo<std::vector<T>>, Foo<int>, ..
template<typename T>
auto bar()
{
return bar_impl(tag<T>{});
}
with usage
using AppleFoo = Foo<ABunchOfStuffForApples>;
auto bar1 = bar<AppleFoo>();
auto bar2 = bar<Foo<ABunchOfStuffForApples>>();
// auto is AppleFoo and so Foo<ABunchOfStuffForApples>

Partial template specialization for template class like std::function

I want to create a function overload to partially specialize a template class. How to make this code work?
template <typename T>
struct Foo;
template <typename Result, typename ... Args>
struct Foo<Result(Args...)>
{
Result Bar()
{
Result t;
return t;
}
};
template <typename ... Args>
void Foo<void(Args...)>::Bar()
{
// do nothing;
}
If it's just a single member function that should expose different behavior if Result=void, then use tag-dispatching:
#include <type_traits>
template <typename T>
struct Foo;
template <typename Result, typename... Args>
struct Foo<Result(Args...)>
{
Result Bar()
{
return Bar(std::is_void<Result>{});
}
private:
Result Bar(std::false_type)
{
Result t;
// Do something
return t;
}
void Bar(std::true_type)
{
// Do nothing
}
};
DEMO
Alternatively, partially-specialize the whole class:
template <typename... Args>
struct Foo<void(Args...)>
{
void Bar()
{
// Do nothing
}
};

Is it possible to expand a parameter pack into different member functions?

Basically what I'm thinking about is:
template<typename... Types>
class Foo
{
void Bar(Types var) {};...
};
which when specialized like this:
Foo<S1, S2, S3> foo;
to expand to:
class Foo
{
void Bar(S1 var){};
void Bar(S2 var){};
void Bar(S3 var){};
};
Obviously, it does not make sense in some way but I'll be happy to see some thoughts.
template<class D, class T>
struct FooHelper {
void Bar(T var) {
auto* self=static_cast<D*>(this);
// here use self instead of this
};
};
template<typename... Types>
class Foo: FooHelper<Foo,Types>...
{
template<class D,class T>
friend struct FooHelper<D,T>;
};
this is how you do what you want to do.
We use use the CRTP to give the base class access to everything in Foo.
Here's a nice C++17 way to do that:
template<typename T>
struct HelpFoo {
void Bar(T) {}
};
template<typename... Types>
struct Foo : HelpFoo<Types>...
{
using HelpFoo<Types>::Bar...;
};
You can let your methods be templated, and use enable_if to enable those in the pack list:
#include <type_traits>
template<class... Ts>
struct foo {
template<class T, std::enable_if_t<
std::disjunction_v<std::is_same<T, Ts>...>, int> = 0>
void bar(T);
};

Is there an idiom/design pattern for restricting templates?

How do one restrict the typename T to specific type?
Consider this:
template <typename T>
struct Worker {
// T can only be certain type allowing specific functionality.
// i.e T needs to be a product of some interface, support some functions, say T::toString(), T::print(), T::get().
// Do something with T
};
This is what I usually end up doing:
struct WorkableType {
std::string toString() { return ""; }
int get() { return 0;}
}
struct WorkabelTypeA : WorkableType {
std::string toString() { return "A"; }
int get() { return 1;}
};
//Similarly
struct WorkableTypeB : WorkableType;
And use static assert and std::is_base_of:
template <typename T>
struct Worker {
static_assert(std::is_base_of<WorkableType, T>::value, "Needs workable type");
// Do something with T
};
Is there any other design pattern, a more C++ way to restrict accidental instantiation of bad typed templates?
Edit: Seems like this would be better solved with C++ Concepts when it becomes the standard. Until then i guess, static_assert is probably more cleaner and verbose than enable_if.
You could use SFINAE and template specialisation:
// type trait that evaluates always to false to use in the primary template
template<typename ... T> struct always_false : std::false_type { };
// primary template
template<typename T, typename Enable = void>
struct Worker {
static_assert(always_false<T, Enable>::value, "Needs workable type");
};
// specialisation
template<typename T>
struct Worker<T, std::enable_if_t<std::is_base_of<WorkableType, T>::value>> {
...
};
You can create traits and check that in your class, So, no need of inheritance. For example:
template <typename T>
using toString_t = decltype(std::declval<T>().toString());
template <typename T>
using get_t = decltype(std::declval<T>().get());
// Use C++17, but can be done in C++11
template <typename T>
using has_toString = std::is_detected<toString_t, T>;
template <typename T>
using has_get = std::is_detected<get_t, T>;
And then
template <typename T>
struct Worker {
static_assert(has_toString<T>::value, "T should have toString");
static_assert(has_get<T>::value, "T should have get");
};
Demo
If you know exactly which types you want to allow, then a traits class is a succinct way to do it:
#include <utility>
// by default nothing is workable
template<class T>
struct is_workable : std::false_type
{
};
template <typename T>
struct Worker {
static_assert(is_workable<T>(), "not a workable type");
// T can only be certain type allowing specific functionality.
// i.e T needs to be a product of some interface, support some functions, say T::toString(), T::print(), T::get().
// Do something with T
};
// define a worker
struct A {};
// make it workable
template<> struct is_workable<A> : std::true_type {};
// define another worker but forget to make it workable
struct B {};
int main()
{
Worker<A> wa{};
// Worker<B> wb{}; // compile error - not workable
};
You can use specializations as it follows:
#include<string>
struct WorkableType {
std::string toString() { return ""; }
int get() { return 0; }
};
struct A {};
struct B {};
template<typename> struct Worker;
template<> struct Worker<A>: WorkableType {};
int main() {
Worker<A> wa;
// this won't compile
// Worker<B> wb;
}

Return variable type depending on sizeof... parameter pack

I wish to create a function that returns a boxed tuple if more than one template argument is passed, and an unboxed value if only one template argument is passed.
For example, I would like foo<int>() to return an int and foo<int, float> to return a something with type std::tuple<int, float>.
All my attempts to achieve this effect have failed.
Consider the following approach using a typetrait struct:
template<typename... T>
struct return_type {
typedef std::tuple<T...> type;
};
template<>
struct return_type<int> {
typedef int type;
};
// ... insert partial specializations for other supported primitive types
template<typename... T>
auto foo() -> typename return_type<T...>::type {
if (sizeof...(T) == 1)
return zap<T...>(); // Returns something of type T, where T is the first parameter
else
return bar<T...>(); // Assume this returns a std::tuple<T...>
}
This will fail to compile because of the differing return types in the body of foo.
Alternatively, here is an attempt using decltype:
<template T>
T singular();
<template... T>
std::tuple<T...> multiple();
template <typename... T>
auto foo() -> decltype(sizeof...(T) == 1 ? singular() : multiple())
{
... // as above
}
This will fail to compile as well because the ternary operator expects both branches to return the same type.
Finally, the naive approach using simple recursive unpacking fails as well:
template<typename T>
T foo() { return T{}; // return something of type T }
template<typename... T>
std::tuple<T...> foo() { return bar<T...>(); // returns a tuple }
This of course fails because the compiler cannot determine which overloaded function to call.
I can't see why something like this isn't possible in C++11 since all the information needed to determine the return type is available at compile time. And yet I'm struggling to see what tools would allow me to do this. Any help and suggestions would be appreciated.
I usually use a struct for specializations:
#include <iostream>
#include <tuple>
namespace Detail {
template <typename...Ts>
struct Foo {
typedef std::tuple<Ts...> return_type;
static return_type apply() { return return_type(); }
};
template <typename T>
struct Foo<T> {
typedef T return_type;
static return_type apply() { return return_type(); }
};
}
template <typename...Ts>
typename Detail::Foo<Ts...>::return_type foo() {
return Detail::Foo<Ts...>::apply();
}
int main ()
{
std::tuple<int, int> t = foo<int, int>();
int i = foo<int>();
}
Ugh, I literally figured out the answer after finally taking a break and grabbing a drink (this is after a couple hours of attempting to find a solution too!).
The answer is a modification of the last approach:
template<typename T>
T foo() { return zap<T>(); /* returns a T */ }
template<typename T1, typename T2, typename... Ts>
std::tuple<T1, T2, Ts...> foo() { return bar<T1, T2, Ts...>(); /* returns a tuple */ }
By using two dummy parameters, the compiler can unambiguously resolve which function is to be called.
I would use tag dispatching.
template<class...Ts> struct many :std::true_type {};
template<class T>struct many :std::false_type {};
template<class...Ts> struct return_value {
typedef std::tuple< typename std::decay<Ts>::type... > type;
};
template<class T>struct return_value : std::decay<T> {};
template<typename T>
T singular( T&& t ) {
return std::forward<T>(t);
}
template<typename... Ts>
typename return_value<Ts...>::type multiple( Ts&&... ts ) {
return { std::forward<Ts>(ts)... };
}
template<typename...T>
typename return_value<T...>::type worker(std::false_type, T&&...t ) {
static_assert( sizeof...(T)==1, "this override is only valid with one element in the parameter pack" );
return singular(std::forward<T>(t)...);
}
template<typename...Ts>
typename return_value<Ts...>::type worker(std::true_type, Ts&&...t) {
return multiple(std::forward<Ts>(t)...);
}
template<class...Ts>
auto foo(Ts&&... t)
-> decltype(worker( many<Ts...>(), std::declval<Ts>()...) )
{
return worker(many<Ts...>(), std::forward<Ts>(t)...);
}
then I would add in perfect forwarding.
I find it easier to reason about overloads than about specializations.