why template parameter which is explicitely given can not be "deduced" - c++

Coming from that question:
Using enum values in combination with SFINAE
I tried to implement:
enum Specifier
{
One,
Two,
Three
};
template <Specifier, typename UNUSED=void>
struct Foo
{
void Bar(){ std::cout << "Bar default" << std::endl;}
};
template <Specifier s , typename std::enable_if<s == Specifier::Two || s == Specifier::One, int>::type>
struct Foo<s>
{
void Bar(){ std::cout << "Bar Two" << std::endl; }
};
int main()
{
Foo< One >().Bar();
Foo< Two >().Bar();
}
Fails with:
> main.cpp:130:8: error: template parameters not deducible in partial specialization:
130 | struct Foo<s>
| ^~~~~~
main.cpp:130:8: note: '<anonymous>'
How to fix that super simple example? I like SFINAE :-)

Put the enable_if in Foo's template argument list:
template <Specifier s>
struct Foo<s, typename std::enable_if<s == Specifier::Two || s == Specifier::One, void>::type>
// same as the default type used before ^^^^
demo.

As the error tells us, template arguments are not deducible in partial specialization. In your example you have tried to place the SFINAE construct in the template parameter list of the specialization, but you need to move it to the template argument list (of the class being specialized) of the specialization declaration.
template <Specifier S>
struct Foo<S, std::enable_if_t<(S == Specifier::Two) || (S == Specifier::One)>>
Applied to your example (cleaned up a bit):
#include <iostream>
#include <type_traits>
enum class Specifier {
One,
Two,
Three
};
template <Specifier, typename = void>
struct Foo {
static void bar() { std::cout << "bar default\n"; }
};
template <Specifier S>
struct Foo<S, std::enable_if_t<(S == Specifier::Two) || (S == Specifier::One)>> {
static void bar() { std::cout << "bar One or Two\n"; }
};
int main() {
Foo<Specifier::One>::bar(); // bar One or Two
Foo<Specifier::Two>::bar(); // bar One or Two
Foo<Specifier::Three>::bar(); // bar default
}
Note that you needn't name the non-used type template parameter in the primary template of the class template Foo.

It's a simple fact that template-arguments in template specializations are not deduceable.
Not that you need it.
Just change the template speialization:
template <Specifier s>
struct Foo<s, std::enable_if_t<s == Specifier::Two || s == Specifier::One, int>>
Though of course the result of std::enable_if_t here being int instead of void makes it somewhat useless.
Also, as others commented, using concepts or at least requires instead of the extra template-argument of the primary template is much more convenient.

Related

Check if a type is a template?

I'm trying to detect whether a type (or more precisely, an identifier as technically a template is not a type) is a template or not, eg to have a function isTemplate which behaves the following way:
template <typename T>
struct X;
struct Y;
template <int N>
struct Z;
isTemplate<X>(); // Should return true
isTemplate<Y>(); // Should return false
isTemplate<Z>(); // Should return true. This one is especially tricky to get the correct results.
How do I implement the isTemplate function?
Note: I've tried the following straightforward implementation :
template <typename T> // If T is a simple type this overload will be selected
consteval bool isTemplate(int) {
return false;
}
template <template <class...> class T> // This overload will be selected if T is a template and fits in as a template template parameter
consteval bool isTemplate(char) { // Dummy char parameter to avoid redefinition
return true;
}
But it doesn't work when it needs to detect a template with non-type parameters.
Expanding on YSC's Answer to another related question, you can add a function overload that uses an auto... parameter pack of non-type template arguments to detect templates accepting non-type arguments.
#include <iostream>
#include <type_traits>
struct foo {};
template<typename T> struct bar {};
template<int I> struct baz {};
template<template<class ...> class T>
constexpr bool is_template() { return true; }
// ADDITIONAL SPECIALIZATION for non-type arguments
template<template<auto ...> class T>
constexpr bool is_template() { return true; }
template<class T>
constexpr bool is_template() { return false; }
int main() {
std::cout << is_template<foo>() << '\n'; // 0
std::cout << is_template<bar>() << '\n'; // 1
std::cout << is_template<baz>() << '\n'; // 1
}
Live Demo
To the best of my knowledge, there is currently no way to define a parameter pack accepting a mixture of both type and non-type template arguments. In practice, this could mean having to write special cases for things like std::array.

How to match only variadic templates with a template template parameter?

Consider the following code:
#include <iostream>
template <template<class...> class C>
struct foo {
foo() { std::cout << "base case\n";}
};
template <template<class> class C>
struct foo< C > {
foo() { std::cout << "single param case\n";}
};
template <template<class,class> class C>
struct foo< C > {
foo() { std::cout << "two param case\n";}
};
template <typename T> struct bar1 {};
template <typename T,typename U> struct bar2 {};
template <typename T,typename U,typename V> struct bar3 {};
template <typename...T> struct barN {};
int main() {
foo<bar1> f;
foo<bar2> g;
foo<bar3> h;
foo<barN> n;
}
Output is (gcc10.2#godbolt):
single param case
two param case
base case
base case
Suppose barX is given and that I have other templates with varying number of type parameters. Some variadic some not.
Is it possible to write a specialization that only matches the variadic template (barN in the above example)?
Very interesting question. Unfortunately the answer is No.
There is no general way to determine if a template had a template parameter pack or just a bunch of regular template parameters with or without defaults.
The reason is that non-variadic templates can bind to variadic template template parameters and the concrete types of a template can bind to a template parameter pack.
So effectively the information is not available via deduction/specialization. And in general this is good - without this feature variadic templates would lose much of their power.
But if we could limit the maximum length of template arguments we could write a trait with a bunch of template specializations. This works because of partial ordering (as you have shown in your question): godbolt
We can determine whether a class template that can be instantiated with 0 template arguments is genuinely variadic or (merely) has defaults for all its non-variadic template arguments, by counting the arguments to an 0-argument instantiation:
template<class> constexpr unsigned argc_v;
template<template<class...> class C, class... A> constexpr unsigned argc_v<C<A...>> = sizeof...(A);
template<template<class...> class, class = void> constexpr bool is_variadic_v = false;
template<template<class...> class C> constexpr bool is_variadic_v<C, std::void_t<C<>>> = argc_v<C<>> == 0;
Then we can use this to build a set of specializations that respectively accept only variadic, 1-argument (with possible default) and 2-argument (with possible default/s) class templates:
template<template<class...> class, class = std::true_type>
struct foo;
template<template<class...> class C>
struct foo<C, std::bool_constant<is_variadic_v<C>>> {
foo() { std::cout << "variable case\n"; }
};
template<template<class> class C>
struct foo<C, std::bool_constant<!is_variadic_v<C> && argc_v<C<void>> == 1>> {
foo() { std::cout << "single param case\n";}
};
template<template<class, class> class C>
struct foo<C, std::bool_constant<!is_variadic_v<C> && argc_v<C<void, void>> == 2>> {
foo() { std::cout << "two param case\n";}
};
I'm a bit disappointed that the latter argc_v tests are necessary (in C++20 mode); I think it's something to do with P0522 / CWG150.
Demo.

Specializing The Same Template Definition For Two Different Types

I am trying to specialize the same template for two different classes in the following way:
template <>
struct TemplateClass<A> {
void method(A x) {
std::cout << x << std::endl;
}
};
template <>
struct TemplateClass<B> {
void method(B x) {
std::cout << x << std::endl;
}
};
Is there a way I can rewrite this to avoid the duplication inside the two specialization definitions?
I do not have control over the definition of TemplateClass. The particular application I have in mind is specialization of fmt::formatter as shown here:
https://fmt.dev/latest/api.html#formatting-user-defined-types
If you look at the definition of struct formatter in fmt/core.h, it has a dummy typename = void parameter:
template <typename T, typename Char = char, typename Enable = void>
struct formatter
This dummy parameter allows you to do SFINAE in specializations:
template <typename T>
struct formatter<T, char, std::enable_if_t<std::is_same_v<T, A> || std::is_same_v<T, B>>>
{
// ...
};
The only duplication you could avoid in your presented code is the std::cout << std::endl; You are outputting 'x' in both but they are of two different types so that is hardly duplication. If the duplication were actually enough to be concerned over you could create a shared base and have both specializations derive from that.

C++ template template parameter

#include <iostream>
using namespace std;
template <typename T = int>
struct Foo {
T t;
Foo() { cout << "Foo" << endl; }
};
template <typename T>
struct Baz {
T t;
Baz() { cout << "Baz" << endl; }
};
template <typename T>
struct Bar {
T t;
Bar() { cout << "Bar" << endl; }
};
template <template <typename X> class T>
struct Bar {
T data;
Bar() : data() { cout << "Bar" << endl; }
};
int main()
{
Bar<Foo<>> a;
Bar<Baz<float>> b;
Bar<int> c;
return 0;
}
I'm just beginning to learn about templates. And I am really confused with template template parameters. I understand that you are passing a template as an argument. In my template class for Bar where it receives a template template argument, what does <typename X> represent? Is typename X a template parameter for class T?
template <template <typename X> class T>
struct Bar {
T data;
Bar() : data() { cout << "Bar" << endl; }
};
Also, when I call my template template argument in the main function, I get errors that there are no default constructors for Bar. Why is that?
template template parameters allow you pass templates to other templates.
They are not concrete types and need to be parameterised order to instaciate them.
In my template class for Bar where it receives a template template
argument, what does <typename X> represent?
From the standard [basic.scope.temp];
The declarative region of the name of a template parameter of a
template template-parameter is the smallest template-parameter-list in
which the name was introduced.
This basically says the name is only available within the that template template's parameters list.
For many cases it is sufficient to just put typename without a name for a template template parameter, but names may serve to document your code.
However an example of when it is useful to give it a name is if another non type template parameter depends on it.
For example, template <template <typename X, X> typename Y>.
With respect too your sample code, you have two problems with the second declaration of Bar. First is that Bar has already been declared to accept a type, not a template.
Your second declaration conflicts as it is declared to accept a template.
What you require here is a specialization of Bar, where the specialization resolves to a single Type, matching the primary template.
For instance,
template <template <typename> class T,typename Y>
struct Bar<T<Y>> {
T<Y> data;
Bar() : data() { cout << "Bar" << endl; }
};
The important thing to notice here is that the template parameters in the specialization can be whatever you need. It is the part after struct Bar that must match the primary template. All of the parameters in the specialization will be deduced from the type passed as the template parameter to your instantiation of Bar.
Your second problem is that you declare a member of Bar to be of type T. T is a template in the second case, and you cannot instantiate a template
without parameterising it.
Here is a working example of your code with the specialization of Bar.
#include <iostream>
using namespace std;
template <typename T = int>
struct Foo {
T t;
Foo() { cout << "Foo" << endl; }
};
template <typename T>
struct Baz {
T t;
Baz() { cout << "Baz" << endl; }
};
template <typename T>
struct Bar {
T t;
Bar() { cout << "Bar" << endl; }
};
template <template <typename > class T,class Y>
struct Bar<T<Y>>
{
T<Y> data;
Bar() : data() { cout << "Bar Specialization" << endl; }
};
int main()
{
Bar<Foo<>> a; //matches the specialization with T = template<typename> Foo and Y=int
Bar<Baz<float>> b; //matches the specialization with T = template<typename> Baz and Y=float
Bar<int> c; //matches the primary template with T=int
return 0;
}
Demo
typename X is only part of the template template parameters signature, you can just aswell write template<template<typename> class T> (without a name for the parameter of T).
Since T is itself a template, you need to instantiate it before you can use it as a class. The signature tells you what the template needs to be instantiated, in this case, it needs one type name.
template<typename X>
struct GenericThing
{
X data;
};
template<template<typename> class T, typename E>
struct Bar
{
T<E> sub; // instantiate T with E
Bar() : sub() { cout << "Bar" << endl; }
};
int main()
{
Bar<GenericThing, int> intbar;
Bar<GenericThing, float> floatbar;
return 0;
}
template <typename T>
void func_template(T& con) {
for (const auto& c : con)
std::cout << c << std::endl;
}
/*
Nested Templates
template <
template <
// # of type args that will be included in the nested template
typename,
...
>
// # of different types yo
typename T1,
...
typename TN
>
*/
template <template<typename, typename> typename V, typename T>
void func_template3(V<T, std::allocator<T>>& vec) {
for (const auto& elem : vec)
std::cout << elem << std::endl;
}
template <template<typename, typename, typename, typename> typename M, typename T1, typename T2>
void func_template4(M<T1, T2, std::less<T1>, std::allocator<std::pair<const T1, T2>>> & dict) {
for (const auto& pair : dict)
std::cout << pair.first << " " << pair.second << std::endl;
}
I just learned C++ a month ago, so please bear with me. The above is the way I personally look at it. the func_template3 and func_template4 provides an example of a template printing vector and map containing any type. I find that paying attention to VS "No instance of function template 'XXXX' matches the argument list error" very useful in trying to determine the composition of built-in types for the data structure that you should include in the template.
For example:
Prior to implementing to func_template4, I used an std::map variable as an argument for func_template3, which then VS prompted me with the following error
So when I was implementing funct_template4, I basically used the "arguments types are:(..." part of the error to guide me on what other built-in types should be included.
I've heard arguments that implementing nested templates are typically unnecessary, since it could have been achieved via func_template1; however, I somewhat disagree because the code that you would write in func_template1 actually depend largely on what data structure you intend to use the template with. Just my 2 cents from a C++ noob.

Possible to use type_traits / SFINAE to find if a class defines a member TYPE?

I have seen this question which allows one to check for the existence of a member function, but I'm trying to find out whether a class has a member type.
In the example below, both evaluate to "false", but I would like to find a way so that has_bar<foo1>::value evaluates to false, and has_bar<foo2>::value evaluates to true.
Is this possible?
#include <iostream>
struct foo1;
struct foo2 { typedef int bar; };
template <typename T>
class has_bar
{
typedef char yes;
typedef long no;
template <typename C> static yes check( decltype(&C::bar) ) ;
template <typename C> static no check(...);
public:
enum { value = sizeof(check<T>(0)) == sizeof(yes) };
};
int main()
{
std::cout << has_bar<foo1>::value << std::endl;
std::cout << has_bar<foo2>::value << std::endl;
return 0;
}
Edit: implementing a specialisation in response to the answers below:
...if you use C::bar in the target template, the template will be
discarded automatically for types that don't have that nested type.
I have tried to do this, but am clearly missing something
#include <iostream>
struct foo1;
struct foo2 { typedef int bar; };
template <typename T, typename U = void>
struct target
{
target()
{
std::cout << "default target" << std::endl;
}
};
template<typename T>
struct target<T, typename T::bar>
{
target()
{
std::cout << "specialized target" << std::endl;
}
};
int main()
{
target<foo1>();
target<foo2>();
return 0;
}
Try this
template<class T>
struct Void {
typedef void type;
};
template<class T, class U = void>
struct has_bar {
enum { value = 0 };
};
template<class T>
struct has_bar<T, typename Void<typename T::bar>::type > {
enum { value = 1 };
};
You cannot obtain a pointer to member to a type member:
template <typename C> static yes check( decltype(&C::bar) ) ;
The subexpression &C::bar will only be valid when bar is a non-type member of C. But what you need to check is whether it is a type. A minimal change to your template could be:
template <typename C> static yes check( typename C::bar* ) ;
If bar is a nested type of C, then that function overload will be a valid candidate (the 0 will be a pointer to whatever C::bar type is), but if C does not contain a nested bar then it will be discarded and the second test will be the only candidate.
There is a different question as of whether the trait is needed at all, since if you use C::bar in the target template, the template will be discarded automatically for types that don't have that nested type.
EDIT
What I meant is that in your approach you need to create a trait for each and every possible nested type, just to generate a template that does or does not hold a nested type (enable_if). Let's take a different approach... First we define a general utility to select a type based on a condition, this is not required for this problem, and a simpler template <typename T> void_type { typedef void type; }; would suffice, but the utility template can be useful in other cases:
// General utility: if_<Condition, Then, Else>::type
// Selects 'Then' or 'Else' type based on the value of
// the 'Condition'
template <bool Condition, typename Then, typename Else = void>
struct if_ {
typedef Then type;
};
template <typename Then, typename Else>
struct if_<false, Then, Else > {
typedef Else type;
};
Now se just need to use SFINAE for class template specializations:
template <typename T, typename _ = void>
struct target {
// generic implementation
};
template <typename T>
struct target<T, typename if_<false,typename T::bar>::type> {
// specialization for types holding a nested type `T::bar`
};
Note that the main difference with your approach is the use of an extra intermediate template (the one for which Substitution will Fail --and Is Not An Error) that yields a void type (on success). This is the reason why the void_type template above would also work: you just need to use the nested type as argument to a template, and have that fail, you don't really care what the template does, as long as the evaluation is a nested type (that must be void) if it succeeds.
In case it is not obvious (it wasn't at first for me) why your approach doesn't work, consider what the compiler needs to do when it encounters target<foo2>: The first step is finding that there is a template called target, but that template takes two arguments of which only one was provided. It then looks in the base template (the one that is not specialized) and finds that the second argument can be defaulted to void. From this point on, it will consider your instantiation to be: target<foo2,void> (after injecting the defaulted argument). And it will try to match the best specialization. Only specializations for which the second argument is void will be considered. Your template above will only be able to use the specialized version if T::bar is void (you can test that by changing foo2 to: struct foo2 { typedef void bar; }. Because you don't want the specialization to kick in only when the nested type is void you need the extra template that will take C::bar (and thus fail if the type does not contain a nested bar) but will always yield void as the nested type.
C++20 Update:
It is now much more easier to check whether a given type contains a specific type definition.
template<typename T>
concept has_bar = requires {
typename T::bar;
};
... so your example code evolves to this:
#include <iostream>
struct foo1;
struct foo2 { typedef int bar; };
template <typename T, typename U = void>
struct target
{
target()
{
std::cout << "default target" << std::endl;
}
};
template<typename T>
requires(has_bar<T>)
struct target<T>
{
target()
{
std::cout << "specialized target" << std::endl;
}
};
int main()
{
target<foo1>();
target<foo2>();
return 0;
}
Example on gcc.godbolt: https://gcc.godbolt.org/z/a15G13
I prefer to wrap it in macro.
test.h:
#include <type_traits>
template<typename ...>
struct void_type
{
using type = void;
};
template<typename ...T>
using void_t = typename void_type<T...>::type;
#define HAS_TYPE(NAME) \
template<typename, typename = void> \
struct has_type_##NAME: std::false_type \
{}; \
template<typename T> \
struct has_type_##NAME<T, void_t<typename T::NAME>>: std::true_type \
{} \
HAS_TYPE(bar);
test.cpp:
#include <iostream>
struct foo1;
struct foo2 { typedef int bar; };
int main()
{
std::cout << has_type_bar<foo1>::value << std::endl;
std::cout << has_type_bar<foo2>::value << std::endl;
return 0;
}