Partially specialize a template on the the first parameter - c++

I tried to do something today that I was surprised to realize didn't work. I have a template that takes a type and a value as parameters. I want to specialize on the type parameter, but leave the value parameter open. Like so
template <class T = void, bool Enabled = false>
struct seFoo {};
template <bool Enabled>
struct seFoo<int, Enabled> {};
// Doesn't work :(
seFoo<false> foo;
However, this leads to a compile error for too few template arguments. It appears the instantiation has to match the signature of the unspecialized template before the compiler will even look at the partial specialization.
Is there a way to get this to work?
If this approach fundamentally isn't possibly, I'm interested in alternative approaches.
Apparently I'm not the only one surprised by this. This article makes the same mistake towards the end.

No, you can't really do this.
Note that a class template partial specialization is not something you can use directly in any way. Its only function is that when you to attempt to use the primary template as normal, if the partial specialization is a match for your template arguments and is the best match among any other explicit / partial specializations, then the partial specialization is used instead of the primary template to generate the definition of that particular class type.
In some cases there are things you can do with default template arguments, defining your own meanings for template arguments, or other such tricks. But there's no way to have one template that can take either a type or a value as its first template argument, and you can't have two class templates or alias templates with the same name in the same scope.

Related

Template class forward declaration with default argument [duplicate]

Suppose we have a class template with default template parameter:
template <typename T = int>
class Foo {};
We can omit angle brackets when creating a variable inside a function:
int main()
{
Foo a; // gets properly deduced as Foo<int>
}
But we can't do that for member variables:
struct S
{
Foo a; // Deduce Foo<int>
};
We can't have derivative types such as this:
Foo* ptr; // Foo<int>*
Foo& ref; // Foo<int>&
int Foo::* mem_ptr; // int Foo<int>::*
std::function<Foo(const Foo&)> fn; // std::function<Foo<int>(const Foo<int>&)>
We can't accept parameters and return them:
Foo Bar(const Foo&); // Foo<int> (*)(const Foo<int>&)
Why? Is this considered a bug in the standard? Is there a proposal to fix it? Are there any actual problems with omitting angle brackets?
My use case:
I have a class template which provides default argument. The template parameter is an expert-only feature that I myself never use but it is there for those 1% of experts who want that total flexibility. Now for other 99% I want to hide the fact that Foo is actually a class template but it doesn't work because users have to type Foo<> when declaring it as a member variable, current solution is this:
template <typename T = int>
class BasicFoo {};
using Foo = BasicFoo<>;
But it complicates implementation code and is not elegant at all.
Is this considered a bug in the standard?
No.
Templates are a named construct which generates another construct (classes/functions/variables) based on a set of parameters. The name of a template is not the name of the construct which it generates. The name of a template is just the name of the template; to name the thing the template generates, you must provide the template parameters.
Foo is the name of a template; Foo<> is the name of a class generated by that template and its associated template parameters.
There are a couple of places where C++ allows a template to be used in such a way that its parameters are deduced from a sequence of expressions. But these are very specific places, created for convenience purposes. They do not exist for the purpose of hiding the fact that a name represents a template rather than the generated construct.
Is there a proposal to fix it?
There is nothing broken to fix. And there are at present no proposals adding changes in this way.
Are there any actual problems with omitting angle brackets?
Define "actual problem". Is it theoretically possible to have the language altered so that, if all of a template's parameters are defaulted, the name of the template can be used without template parameters to simultaneously mean the template and the thing the template generates?
It is probably possible. But it would be complicated to specify. You would need a serious spec-doctor, one who understands the C++ grammar at a deep level, to know for sure whether it is possible, and what exactly would need to be changed to do it.
But at the end of the day, it would only ever be useful for a small, select set of templates: templates that have default values for all of its parameters. The real question is whether that is a common enough case to be worth the effort.
I don't consider myself a language expert, but my stance would be that the problem your proposal tries to tackle is solved much simpler in the same way std::(basic_)string does it.
We have
template<
class CharT,
class Traits = std::char_traits<CharT>,
class Allocator = std::allocator<CharT>
> class basic_string;
and then a set of typedefs for "non-expert" users, such as std::string for std::basic_string<char>.
If an expert user wants to make use of the other template parameters, they can themselves define a type alias, which is nice and coherent with the above. Moreover, this cleanly separates the template from the types that are created from it.
Your suggestion of allowing templates with defaults for all parameters to be named by MyTemplate alone, instead of requiring MyTemplate<>, or making use of using MyTemplate = MyBasicTemplate<>;, has the following issues:
It complicates the grammar and specification of the language. You need to touch the allowed syntax of all the contexts mentioned in your question, adding the ability to use a template name where a type name would be expected, but only if the relevant template has default values for all template parameters. And if you don't change all of them, you introduce weirdly inconsistent behavior.
There is some overlap between your suggestion and CTAD, but CTAD is decidedly about reducing type verbosity for initialization. CTAD offers significant comfort within its scope and is extensible through deduction guides, whereas your proposal's syntactic sugar is only relevant in a tiny usage niche, with much smaller benefits.
There is the danger of accidentally using the wrong template parameters (did you mean the default template parameters or did you just forget to specify the ones you wanted?). Even if that is not a concern in your use case, the standard would have to concern itself with that potential issue.
There is also the danger of your suggestion conflicting with deduction guides. Who should win?
Your problem is easily and conveniently solved with existing language tools (see above). I disagree that this "complicates" implementation code (complexity is literally only increased by a single typedef/using, (re)naming your template is absolutely trivial work) or that it is inelegant.
Overall, the problem you intend to solve (saving library implementers a using, or users a <> (or using), exclusively for all-defaulted templates) is fringe at best and will not be a sufficient motivation for significantly altering several core aspects the language. That's my prediction at least.

Is there any proposal in the pipeline to allow any parameter in a template?

The problem with templates is that you must specify a particular item you want as a parameter, such as a typename, a template or a value. However, you can't say, specialize the template based on if the next parameter is any of those three.
I was thinking that if there will be a way to specialize based on these parameters like in the following example:
template <...Xs>
struct X;
template <template <typename...> class TT>
struct X<TT> {};
template <typename T>
struct X<T> {};
template <typename T, T I>
struct X<I> {};
This is a template that takes a parameter pack of unspecified parameters, and is can only be accessed though specialization.
This allows the ability to have more control over template specialization and accept any parameter list. Does anyone know if there is anything being discussed about a feature like this?
If not, what's the proposal process?
Universal Template Parameters was submitted for the Prague meeting in Feb 2020. It introduces template auto X as the syntax for an arbitrary template entity. It was discussed in EWG-I and received feedback. I believe the authors will bring it back for the next meeting in Varna.
Well, it would appear that there isn't an official proposal out there as yet, but there is a suggestion as to how it could be done here. It is attempting to reuse the keyword template in a naked context to define a template parameter that will take a unspecified template parameter type (UTPT).
I had written another proposal before I knew about that one here. It uses no keyword to indicate that the template parameter type (TPT) is unspecified.
It shows a side by side comparison that shows a real world example of a template which would benefit from having a UTPT and how it will look with the suggestion implemented.
I hope you might find these interesting and if so, please comment on either one of them, so that they can get more attention.

Implicit instantiation of specialization

I can't understand why the standard first defines template instantiation for templates as follows N3797::14.7/4 [temp.spec]:
The act of instantiating a function, a class, a member of a class
template or a member template is referred to as template
instantiation.
But further everywhere it uses the instatiation of the specialization, like the following N3797::14.7/4 [temp.spec]:
An instantiated template specialization can be either implicitly
instantiated (14.7.1) for a given argument list or be explicitly
instantiated (14.7.2).
I don't understand that. A template itself is a different concept than the template specilization, which could be an explicit specialization or a partial specialization. For instance N3797::14.5.5/1 [temp.class.spec]:
The primary template shall be declared before any specializations of
that template.
My question is about why the Standard first declare the instatiation concept for templates, but further it applies that concept for template specializations?
Moreover N3797::14.7/4 [temp.spec] defines the specialization concept as follows:
A specialization is a class, function, or class member that is either
instantiated or explicitly specialized (14.7.3).
So, the partial specialization is not a specialization, is it? I'm totally confused by those concepts. Couldn't you clarify it a bit?
This is a similar question here.
And now,I try to answer this question again.
A template is a type of infinite, so we can not instantiate a template, we can only be instantiated template specialization.
Implicitly instantiated, the current compilation unit requires the use of the template code, the compiler automatically instantiated template specialization.
Explicitly instantiated, we manually enter the code causes the compiler to instantiate a template specialization.
explicit specialization, given all the template parameters, and gives a non-generic code. Once the template type match, then instantiate this specialization.
Partial specialization, some parameters are given template and gives a non-generic code. Once the template type match, then instantiate this specialization.

Why does the Standard prohibit friend declarations of partial specializations?

The C++ standard prohibits friend declarations of partial specializations. (ยง14.5.3/8):
Friend declarations shall not declare partial specializations. [Example:
template<class T> class A { };
class X {
template <class T> friend class A<T*>; //error
};
--end example]
Other questions, e.g. this one,
have received answers that invoke this prohibition, but I would like to know the
rationale. I don't see it and can't find it with my favourite search engine. I
can find however that it goes right back to the C++98 standard, so presumably
the rationale is quite basic and clear. Can someone explain it to me?
I don't have a reference but I suspect that this is because it would result in the partial specialization being declared in the scope of the friend-declaring class rather than the scope of the template in question, and rather than creating a bunch of rules to force the friend declaration to result in the specialization being in the correct scope, they simply prohibit it.
Here is some undirect explanation:
http://www.cprogramming.com/tutorial/template_specialization.html
A final implementation detail comes up with partial specializations:
how does the compiler pick which specialization to use if there are a
combination of completely generic types, some partial specializations,
and maybe even some full specializations? The general rule of thumb is
that the compiler will pick the most specific template
specialization--the most specific template specialization is the one
whose template arguments would be accepted by the other template
declarations, but which would not accept all possible arguments that
other templates with the same name would accept.
I infer that maybe it is not permitted to prevent any ambiguity in the determination of specialization type.

Template-like declaration for function overloads

Can I make generic function declarations at the start of my header file?
I can do template<class t> t func(t); then specialize it, but
Template Specialization VS Function Overloading
says not to do that.
First, you can surely declare a template function and then define it, and/or define specializations. But...
Function specializations must be full specializations, that is, you cannot partially specialize a template function. Now, while you can actually specialize the function template, providing overload may have advantages (and disadvantages), but in most cases it will be a better option.
You might want to read this: http://www.gotw.ca/publications/mill17.htm