template template argument deduction with sfinae - c++

The template template argument can't be deduced for both foo and foo2.
If I remove the sfinae part, the template template argument was successfully deduced for both foo and foo2.
How to fix either the span class or foo and foo2?
Thanks.
Test (also at godbolt.org)
#include <type_traits>
template<typename T>
using enable_if_t_const = typename std::enable_if<
std::is_const<T>::value
>::type;
template<typename T, typename=void> class span;
template<typename T>
class span<T, enable_if_t_const<T>> {
public:
explicit span(const T* const data) {}
};
template <typename T, template<typename> class S>
void foo() {}
template <typename T, template<typename> class S>
void foo2(S<T>& s) {}
int main() {
int arr[] = {1};
span<const int> s(arr);
foo<const int, span>();
foo2(s);
return 0;
}

This is because, although you have a default template parameter, span isn't a template <typename> class S. It's a template <typename, typename> class S.
The easiest fix is to change it to
template <typename T, template<typename...> class S>
void foo2(S<T>& s) {}
So that you can accept any S that takes any number of types (although we only use it with one).
Demo

Related

Check whether a default-deleted function template is explicitly specialized for a specific type?

(This question has been significantly edited, sorry.)
Suppose I have several non-constexpr function templates, which default to being deleted:
template <typename T> void foo() = delete;
template <typename T> int bar(int x) = delete;
// etc.
and have some explicit specialization as an exception to the general-case deletion.
I want to write code (e.g. a trait class?) which, given the identifier of one of these functions and a type T, detects, at compile-time, whether the specified function is explicitly specialized for type T. The code needs to be generic, i.e. not a separate detector for each of the functions.
Notes:
Looking for a C++11 solution.
We may assume the specified function is deleted by default - if that helps.
Ideally, it would like like instantiation_exists<decltype(foo), foo, int>::value or instantiation_exists<int>(foo, tag<int>) or instantiation_exists(foo, tag<int>) or something along those lines.
Edit: #Jarod42's wrote up an SFINAE example in a comment on an earlier version of this question, which was about a per-single-function detector. I tried to generalize/genericize it using a template-template parameter:
#include <type_traits>
template <typename T> void foo() = delete;
template <> void foo<int>() {}
template <template<typename U> typename F, typename T, typename = decltype(F<T>()) >
std::true_type test(int);
template <template<typename U> typename F, typename T>
std::false_type test(...);
template <typename T>
using foo_is_defined = decltype(test<foo<T>, T>(0));
static_assert(foo_is_defined<int>::value);
static_assert(not foo_is_defined<int*>::value);
but that was a wash (Coliru).
We cannot pass template function, or overloads in template parameter.
We can turn those function in functor:
template <typename T>
struct identity_type
{
using type = T;
};
template <typename F, typename T, typename = decltype(std::declval<F>()(identity_type<T>{})) >
std::true_type test(int);
template <typename F, typename T>
std::false_type test(...);
auto foos = [](auto tag, auto&&... args)
-> decltype(foo<typename decltype(tag)::type>((decltype(args))(args)...))
{
return foo<typename decltype(tag)::type>((decltype(args))(args)...);
};
template <typename T>
using is_foo = decltype(test<decltype(foos), T>(0));
Demo
I use generic lambda, so C++14.
in C++11, it would be really verbose:
struct foos
{
template <typename T, typename... Ts>
auto operator()(identity_type<T>, Ts&&... args) const
-> decltype(foo<T>(std::forward<Ts>(args)...))
{
return foo<T>(std::forward<Ts>(args)...);
};
};

Deducing template parameter types for each type in parameter pack

Let's say I have a type
template <class T, class U>
class Pass
{
};
I want to make a class that will accept a list of Pass objects, each with arbitrary T and U and make 3 std::tuples.
Something like this:
template<template <typename P1, typename P2> class... T>
class Test
{
public:
Test(T<P1, P2>... passes) {}
std::tuple<T<P1, P2>...> tuple1;
std::tuple<P1...> tuple2;
std::tuple<P2...> tuple3;
};
And then create an instance:
Test t{ Pass<int, float>(), Pass<int, int>(), Pass<std::string, float>() };
Is it possible?
Yes:
template <typename... >
struct Test;
template <typename... T, typename... U>
struct Test<Pass<T, U>...>
{
Test(Pass<T, U>...);
std::tuple<Pass<T, U>...> tuple1;
std::tuple<T...> tuple2;
std::tuple<U...> tuple3;
};
template <typename... T, typename... U>
Test(Pass<T, U>...) -> Test<Pass<T, U>...>;
We need the deduction guide here because class template argument deduction only implicitly considers the primary template's constructors and the primary in this case has no constructors.
Note that this declaration:
template <template <typename P1, typename P2> class... T>
struct X { };
Means the same thing as this declaration:
template <template <typename, typename> class... T>
struct X { };
Which means a parameter pack of binary class templates - not specific types. Such a class template might be instantiated with:
X<Pass, std::pair, std::vector> x;

Templated Using with Nested Template

The following code does not work because the inferred template parameter F is std::tuple, whereas I want it to be Foo - the former takes two template parameters and the latter takes one.
#include <tuple>
template <typename T>
using Foo = std::tuple<int, T>;
template <template <typename> class F>
void foo(F<std::string> bar) {}
void test() {
foo(Foo<std::string>());
}
Is there any way to make type inference work with the using statement rather than turning Foo into it's own class?
#include <tuple>
template <typename T>
class Foo {
std::tuple<int, T> bar;
};
template <template <typename> class F>
void foo(F<std::string> bar) {}
void test() {
foo(Foo<std::string>());
}
More Info
I am using C++17's std::variant along with using to alias types that are generic on a single type and I would prefer to declare these with using statements rather than creating wrapper classes for each one. Something like this:
// Assuming Plus, Minus, etc all exist
template <typename T>
using Operation = std::variant<Plus<T>, Minus<T>, Times<T>>;
Building a Haskell-Style Functor
The point of this exercise is to build a small functor library loosely based on Haskell's functor typeclass. I have defined the "typeclass" like this:
template <template <typename> class F>
class Functor {
public:
template <typename T, typename U>
static F<U> fmap(std::function<U(T)> f, F<T> functor);
};
But I also wanted to add some sugar so that you can create a general mapper that will map a function over any function type without pre-specifying the functor type:
template <typename T, typename U>
struct FMap {
FMap(std::function<U(T)> f) : f_(f) {}
template <template <typename> class F>
F<U> operator()(F<T> functor) {
return Functor<F>::fmap(f_, functor);
}
private:
std::function<U(T)> f_;
};
template <typename T, typename U>
FMap<T, U> fmap(std::function<U(T)> f) {
return FMap<T, U>(f);
}
This works well with a simple value-wrapper functor:
template <typename T>
class Value {
public:
Value(T value) : value_(value) {}
const T& value() const {
return value_;
}
private:
T value_;
};
template <>
template <typename T, typename U>
Value<U> Functor<Value>::fmap(std::function<U(T)> f, Value<T> value) {
return Value<U>(f(value.value()));
}
void test() {
std::function<std::string(int)> fn = [](int x) {
return std::to_string(x);
};
auto result = fmap(fn)(Value(42));
// result.value() == "42"
}
Now I am trying to get it to work with a more complicated type that uses std::tuple or std::variant like in the above example.
template <>
template <typename T, typename U>
Foo<U> Functor<Foo>::fmap(std::function<U(T)> f, Foo<T> value) {
return Foo<U>(std::get<0>(value), f(std::get<1>(value)));
}
void test() {
std::function<std::string(int)> fn = [](int x) {
return std::to_string(x);
};
// This is the desirable syntax but it doesn't build
// fmap(fn)(Foo<int>(42, 7));
// This builds but it's super ugly
fmap(fn).operator()<Foo>(Foo<int>(42, 7));
}
Based on the response by SkepticalEmpiricist below, I am thinking that type aliases may not be the way to go here and instead I will have to introduce small wrapper classes - unless there is an SFINAE approach that would get this working.
This library is mostly a curiosity and a means for me to explore some more advanced template concepts - thanks for the help!
So first attempt before we start digging for some SFINAE based trickery to try circumvent the unavoidable:
Alias templates are never deduced by template argument deduction
We could "deduce" the template arguments for the compiler ourselves like this:
#include <tuple>
template <typename T>
using Foo = std::tuple<int, T>;
template <template <typename ...> class F, typename T, typename ...Ts>
void foo(F<T, std::string, Ts...> bar) {}
void test() {
foo(Foo<std::string>());
}
So now we have it compiling for your foo(Foo<std::string>()); call with Foo being the alias template over std::tuple and, more importantly, foo() is still specialized only for Foo<std::string>.
However, to support usage simultaneously of foo() for both the std::tuple alias template and the wrapper class for example, we still don't have it compiling error-free. As in, if we now comment-out the tuple-flavor Foo and bring back in the wrapper class Foo then calling our rewritten foo() will not compile.
To address the issue, let's give it a try with SFINAE to the rescue and replace the last declaration of foo() with this code:
template <template <typename ...> class F, typename T, typename ...Ts,
typename std::enable_if_t<std::is_same<F<T, Ts...>,
std::tuple<T, Ts...>>::value >* = nullptr>
void foo(F<T, std::string, Ts...> bar) {}
template <template <typename> class F>
void foo(F<std::string> bar) {}
Now you can call foo() for instances of both wrapper class of tuples and alias template for tuples. You could implement in the same fashion for std::variant as well.
With:
template <typename T> using Foo = std::tuple<int, T>;
template <template <typename> class F> void foo(F<std::string> bar) {}
void test() { foo(Foo<std::string>()); }
Foo<std::string> is std::tuple<int, std::string>.
so test is
void test() { foo(std::tuple<int, std::string>()); }
How do you expect compiler deduce from tuple from which alias it come ?
we might have
template <typename T> using Bar = std::tuple<int, std::string>;
template <typename T> using Bar2 = std::tuple<some_trait<T>::type, some_trait<T>::type2>;
// ...
A possible workaround might be:
template <typename T, typename U>
Foo<U> fmap(std::function<U(T)> f, Foo<T> value)
{
return Foo<U>(std::get<0>(value), f(std::get<1>(value)));
}
With calling syntax:
fmap(fn, Foo<int>(42, 7));

Retrieve the template a type is instantiated from

How can I retrieve the template a type was originally instantiated from?
I'd like to do the following:
struct Baz{};
struct Bar{};
template <typename T>
struct Foo {};
using SomeType = Foo<Bar>;
template <typename T>
using Template = get_template<SomeType>::template type<T>;
static_assert(std::is_same<Foo<Baz>, Template<Baz>>::value, "");
I know I can achieve this through partial specialization, but this forces me to specialize get_template for every template I want to use it with:
template <typename T>
struct get_template;
template <typename T>
struct get_template<Foo<T>>
{
template <typename X>
using type = Foo<X>;
};
live example
Is there a way around this limitation?
You could do something like that, using a template template parameter (should work for templates with any number of type arguments):
template <typename T>
struct get_template;
template <template <class...> class Y, typename... Args>
struct get_template<Y<Args...>> {
template <typename... Others>
using type = Y<Others...>;
};
Then to get the template:
template <typename T>
using Template = typename get_template<SomeType>::type<T>;
As mentioned by #Yakk in the comment, the above only works for template that only have type arguments. You can specialize for template with specific pattern of type and non-type arguments, e.g.:
// Note: You need the first size_t to avoid ambiguity with the first specialization
template <template <class, size_t, size_t...> class Y, typename A, size_t... Sizes>
struct get_template<Y<A, Sizes...>> {
template <class U, size_t... OSizes>
using type = Y<U, OSizes...>;
};
...but you will not be able to specialize it for arbitrary templates.
DEMO (with Foo and std::pair):
#include <type_traits>
#include <map>
struct Bar{};
template <typename T>
struct Foo {};
using SomeType = Foo<Bar>;
template <typename T>
struct get_template;
template <template <class...> class Y, typename... Args>
struct get_template<Y<Args...>> {
template <typename... Others>
using type = Y<Others...>;
};
template <typename T>
using Template = typename get_template<SomeType>::type<T>;
static_assert(std::is_same<SomeType, Template<Bar>>::value, "");
static_assert(std::is_same<Foo<int>, Template<int>>::value, "");
using PairIntInt = std::pair<int, int>;
using PairIntDouble = std::pair<int, double>;
template <typename U1, typename U2>
using HopeItIsPair =
typename get_template<PairIntDouble>::type<U1, U2>;
static_assert(std::is_same<PairIntDouble, HopeItIsPair<int, double>>::value, "");
static_assert(std::is_same<PairIntInt, HopeItIsPair<int, int>>::value, "");
Not sure I got the question. Would this work?
#include<type_traits>
#include<utility>
template<typename V, template<typename> class T, typename U>
auto get_template(T<U>) { return T<V>{}; }
struct Baz{};
struct Bar{};
template <typename T>
struct Foo {};
using SomeType = Foo<Bar>;
template <typename T>
using Template = decltype(get_template<T>(SomeType{}));
int main() {
static_assert(std::is_same<Foo<Baz>, Template<Baz>>::value, "");
}
You can generalize even more (SomeType could be a template parameter of Template, as an example), but it gives an idea of what the way is.

Template class specialization with a template template argument

#include <tuple>
#include <iomanip>
template <typename T, typename ...L>
struct foo{};
template <typename T>
struct bar{
using toto = T;
};
template <template<typename T, typename ...L> class F>
struct bar<F>{
using toto = T
};
int main(){
bar<foo<int,char,char>> a;
}
I want to specialize bar when the argument is a class that has at least one template argument <typename T, typename ...L>
I tried :
template <template<typename T, typename ...L> class F>
struct bar<F<T,L...>>{
using toto = T
};
and
template <template<typename , typename ...> class F, typename T, typename ...L>
struct bar<F<T,L...>>{
using toto = T
};
which may have made sense, but I couldn't get it right
You forgot a lot of stuff on your sample, syntactically speaking
template <typename T, typename... L>
struct foo{};
template <typename T>
struct bar {
using toto = T; // Semicolon missing
};
template <template<typename, typename...> class F, typename T, typename... L>
struct bar<F<T,L...>> { // Wrong pack expansion
using toto = T;
};
int main() { // () missing
bar< foo<int,char,char> > a; // Pass the parameters to foo since you're
// partially specializing bar to just do that
}
Example on ideone
Your ideone code just has a bunch of typographical errors:
struct bar<F<T,...L>>{
//should be
struct bar<F<T,L...>>{
//missing brackets
int main{
//missing semicolon
using toto = T
bar<foo, int,char,char> a;
//should be
bar<foo<int,char,char>> a;
There's a few syntatic issues here.
bar is a template that takes one type argument. So any partial or explicit specialization of bar must also take one type argument.
template <template<typename T, typename ...L> class F>
struct bar<F> {
Here, the T and L names are irrelevent, and really you're specializating on a template template. That doesn't match. You'd have to specialize on a specific instantiation of F:
template <template<typename , typename ...> class F,
typename T, typename... L>
struct bar<F<T, L...>> {
You're missing a semicolon:
using toto = T;
^^
Your declaration of main is missing parentheses:
int main() {
bar<foo<int,char,char>> a;
}