Must an unused function in a template class be valid? - c++

In a template I have some functions which are only valid for certain template types. GCC seems to be happy with this, but I'm not sure it is valid. Unlike typical SFINAE the function itself is not a template.
template<typename T>
struct generic {
T item;
void get_limited() {
item.limited();
}
};
Provided I don't call get_limited, is it okay to instantiate this class with a type that does not implement limited?
If no, how can I solve this? I have a generic container class where certain features are enabled based on the allocate it is storing (so not directly on the type as above, but still a template parameter).

Template functions are instantiated on demand, so if there is no use of the function it need not be correct, at least for some possible instantiations. The standard does state that if a template is not valid for any instantiating type, the program is ill-formed (although the compiler is not required to diagnose it) even if it is never instantiated.
This feature is used in the standard library in different parts, where the requirements of a single function might be stricter than the general requirements that the template places on the instantiating types. For example, in the case of std::map, in general, the value type does not need to be default constructible, but if you want to use operator[] then it needs to be, since that operator might need to create an empty element if the key is not present.

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.

std::optional with optional variadic template [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.

Static polymorphism: How to define the interface?

Below is a very simple example of what I understand as static polymorphism. The reason why I'm not using dynamic polymorphism is that I do not want to obstruct inlining of functions of PROCESSOR in op.
template <class PROCESSOR>
void op(PROCESSOR* proc){
proc->doSomething(5);
proc->doSomethingElse();
}
int main() {
ProcessorY py;
op<ProcessorY>(&py);
return 0;
}
The problem with this example is: There exists no explicit definition of what functions a PROCESSOR has to define. If one is missing, you will just get a compile error. I think this is bad style.
It also has a very practical drawback: On-line assistance of IDEs cannot of course show you the functions that are available on that object.
What is a good/official way to define the public interface of a PROCESSOR?
There exists no explicit definition of what methods a PROCESSOR has to define. If one is missing, you will just get a compile error. I think, this is bad style.
It is. It is not. It may be. It depends.
Yes, if you want to define behavior in this way, you may want to also restrict the content, that template parameters should have. Unfortunately, it is not possible to do this "explicitly" right now.
What you want is constraints and concepts feature, that was supposed to appear as part of C++ 11, but was delayed and is still not available as of C++ 14.
However, getting compile-time error is often the best way to restrict template parameters. As an example, we can use std library:
1) Iterators.
C++ library defines few types of iterators: forward_iterator, random_access_iterator and others. For each type, there is a set of properties and valid expressions defined, that are guaranteed to be available. If you used iterator, that is not fully compatible with random_access_iterator in container, that requires random_access_iterator, you will get compiler error at some point (most likely, when using dereference operator ([]), which is required in this iterator class).
2) Allocators.
All containers in std library use allocator to perform memory allocation/deallocation and objects construction. By default, std::allocator is used. If you want to exchange it with your own, you need to ensure, that it has everything, that std::allocator is guaranteed to have. Otherwise, you will get compile-time error.
So, until we get concepts, this is the best and most widely used solution.
First, I think there is no problem with your static polymorphism example. Since it's static, i.e. compile-time resolved, by definition it has less strict demands regarding its interface definition.
Also it's absolutely legitimate that the incorrect code just won't compile/link, though a more clear error message from the compiler would be nicer.
If you, however, insist on interface definition, you may rewrite your example the following way:
template <class Type>
class Processor
{
public:
void doSomething(int);
void doSomethingElse();
};
template <class Type>
void op(Processor<Type>* proc){
proc->doSomething(5);
proc->doSomethingElse();
}
// specialization
template <>
class Processor<Type_Y>
{
// implement the specialized methods
};
typedef Processor<Type_Y> ProcessorY;
int main() {
ProcessorY py;
op(&py);
return 0;
}

Can standard container templates be instantiated with incomplete types?

Sometimes it's useful to instantiate a standard container with an incomplete type to obtain a recursive structure:
struct multi_tree_node { // Does work in most implementations
std::vector< multi_tree_node > child;
};
struct trie_node { // Does not work in most implementations
std::map< char, trie_node > next;
};
This tends to work because containers don't have members of type value_type or member functions that pass or return any value_type objects by value. The Standard doesn't seem to say very much about incomplete template arguments, but there is one bit under C++11 §17.6.4.8 [lib.res.on.functions], "requirements on other functions":
In particular, the effects are undefined in the following cases: … if an incomplete type (3.9) is used as a template argument when instantiating a template component, unless specifically allowed for that component.
Does this make the above constructs illegal, even though the instantiations are not in block scope? Does this fall under "operations on types used to instantiate standard library template components" (also 17.6.4.8)? Or is a library implementation forbidden to incur template instantiations that might fail for incomplete types when all specifically required instantiations succeed?
Edit: Since only functions may call and instantiate other functions, restricting "operations on types…" to those in block scope would seem to hold the contents of member functions to a stricter requirement than the contents of signatures and member class definitions. After all, it certainly doesn't make sense to do anything with a multi_tree_node until the type is complete. And this extends to the std::unique_ptr which explicitly supports an incomplete type argument, even when used in block scope.
Edit 2: Serves me right for not bothering to test the trie_node example — and I've even tried it before. It's the same as the example of breakage in the article that #Ise linked. However, while the article seems to take for granted that "nothing like that could work," the solution seems simple to me — std::map's internal tree_node class should be a non-member template, not a member non-template class.
Anyway, that article establishes design intent pretty well, so I guess my nitpick about being under the subheading of "requirements on functions" is only just that.
Here's my attempt at an interpretation:
The standard simply says you mustn't do this, even though any given concrete implementation may have no problem supporting such a construction. But imagine for example if someone wanted to write a "small vector" optimization by which a vector always contains space for, say, five elements. Immediately you'd be in trouble because you'd have a self-referential type. This would be a problem even if the vector employed some sort of static branching depending on the size of the value type.
Therefore, in order to not preclude implementations from including such constructions, the standard simply says that you must only use complete types. In other words, the fact that most containers only contain references or pointers to the value type is an implementation detail rather than a standard requirement.
Just to clarify this: if you define your own class template, it is perfectly possible to design it in such a way that it explicitly supports incomplete types. An example from the standard is std::unique_ptr, which is perfectly happy with the incomplete type parameter T[] (or even void).
Personally, I feel the wording instantiating in 17.6.4.8/2 is a little
ambiguous, but according to
this article,
the standard's intent seems not to allow recursive data type using
standard containers.
On a related note, VC2005 issues an error for
class C { std::deque< C > x; };, while it compiles
class C { std::vector< C > x; };...
However, in my understanding, this restriction is just for expanding the
freedom of the implementation of standard containers.
So as Kerrek SB mentioned, there can be containers which allow
recursive data structure, and
Boost.Container
seems to provide this facility.
In general, using an incomplete type as a template parameter to a standard library component is UB. Here's the reference:
If an incomplete type ([basic.types]) is used as a template argument when instantiating a template component or evaluating a concept, unless specifically allowed for that component.
Note that since c++17, explicit permission has been granted to std::vector to allow incomplete types. Here's the reference:
An incomplete type T may be used when instantiating vector if the allocator meets the allocator completeness requirements. T shall be complete before any member of the resulting specialization of vector is referenced.
So in your example, multi_tree_node is well formed, but trie_node is UB.

Enforcing Common Method Names

Note: This is a follow-up question to this.
I have a group of template classes that do completely different things in completely different ways using completely different datatypes. They do, however, share common method names. For example, Get(), Set(), Resize(), etc. are valid methods for each of the classes in question. Additionally, they accept arguments in the same order. This allows for generalized non-friend, non-member functions to work on each of the classes. A simplified example:
template <typename Class, typename Datatype>
void Insert(const Class<Datatype>& Object, const std::size_t Index, const Datatype Value)
{
Object.Resize(Object.Size() + 1);
for (std::size_t CurrentIndex = Object.Size() - 1; CurrentIndex > Index; CurrentIndex--)
{
Object.Set(CurrentIndex, Object.Get(CurrentIndex - 1));
}
Object.Set(Index, Value);
}
Right now, I'm just relying on my own memory to define all the appropriate methods properly. Is there a way to have the compiler enforce the definition of the proper methods? If not, is there a better way to do this?
What you are looking for is called "concepts" and used to be a feature in C++0x but got dropped from the new standard.
There are some implementations for C++03 out there, but they are harder to use and might be not worth the trouble. e.g. Boost Concept Checking
gcc also has the --enable-concept-check option although I'm not entirely sure how that works with user code.
The compiler already enforces the definition of those methods by refusing to let you instantiate the template for types that don't provide the necessary methods.
Unfortunately, compilers' error messages for uninstantiable templates are often difficult to decipher.
You can document the type requirements in comments. Take a look at how the C++ standard defines type requirements like Assignable, CopyConstructible, EqualityComparable, LessThanComparable, and the requirements for types in the standard containers.
The compiler will enforce the correct interface by failing to compile any call to a nonexistent function; perhaps the problem is that the error messages are too cryptic?
You could define a base class which declares the required interface as non-virtual functions. The base class functions have no definitions (except where it makes sense to have an optional function with a default implementation).
Then, if the template argument derives from this base class, failure to implement a required function will cause a link error (due to attempting to call the base class functions, which are not defined). This will most likely be easier to diagnose than a typical template-related compile error.
You could go one step further and include a compile-time check that the template argument is derived from the base class; I'll leave that as an exercise for the reader. Or it might be better to just document the purpose of the base class, and leave it up to the user whether to use it or not.
You can use an interface.
See this question: How do you declare an interface in C++?