This question came up as I answered this question: does the standard allow and make any guarantees about friend-ing standard library classes and/or functions?
In this particular case, the situation the question was whether:
class MyUserDefinedType
{
friend struct std::default_delete<MyUserDefinedType>;
private:
~MyUserDefinedType() { }
}
is guaranteed to allow MyUserDefinedType to be stored in a std::unique_ptr<MyUserDefinedType> or std::shared_ptr<MyUserDefinedType> object with the default deleter.
In general, are classes described in the standard library required to implement their functionality directly, or can they use any arbitrary level of indirection? For example, is it possible that
std::default_delete<MyUserDefinedType> is actually a using alias of a class defined in an inner namespace of std, in which case the friend declaration would be illegal
or
std::default_delete<MyUserDefinedType> calls some other class that actually does the deleting, in which case the friend declaration would not have the desired effect
or something else along those lines?
My guess is that this is UB not guaranteed to work but I am curious if this is addressed specifically by the standard.
This specific example given above works for clang trunk (w/libc++) and GCC 4.7.2 (w/libstdc++), FWIW
is it possible that std::default_delete<MyUserDefinedType> is actually a using alias of a class defined in an inner namespace of std, in which case the friend declaration would be illegal?
No. Per Paragraph 20.7.1.1.2 of the C++11 Standard:
namespace std {
template <class T> struct default_delete {
constexpr default_delete() noexcept = default;
template <class U> default_delete(const default_delete<U>&) noexcept;
void operator()(T*) const;
};
}
The fact that it has to be a class template is explicitly specified. This means it cannot be an alias template. If that was the case, it would also be impossible to specialize it.
is it possible that std::default_delete<MyUserDefinedType> calls some other class that actually does the deleting, in which case the friend declaration would not have the desired effect?
Yes. Nothing in the Standard specifies that the call cannot be done by some internal helper. Per Paragraph 20.1.1.2:
void operator()(T *ptr) const;
3 Effects: calls delete on ptr.
4 Remarks: If T is an incomplete type, the program is ill-formed.
This only specifies what the effect of invoking the call operator on the default_delete<> functor should be, not how this shall be achieved concretely (whether directly inside the body of the call operator, or by delegating the task to some member function of some other class).
In general, are classes described in the standard library required to implement their functionality directly, or can they use any arbitrary level of indirection?
In general an implementation may indirect as much as it wants. Have e.g. a look at the implementations of standard containers and their iterators - or just use them wrong and see which templates are involved from the error messages. However, since default_delete is nothing magic, that should be a one-liner, you can expect it to do the work itself, but it's not guaranteed.
My guess is that this is UB but I am curious if this is addressed specifically by the standard.
It's not UB, it's just unspecified.
You could be sure if you just specialized default_delete<MyUserDefinedType> (it is allowed to specialize standard libraray templates), but I would not do that.
I would not use friendship at all, especially not if it comes to templates that have not been specialized. Consider this:
//your code
class MyUserDefinedType
{
friend struct std::default_delete<MyUserDefinedType>; //for deletion
private:
int veryPrivateData;
~MyUserDefinedType() { }
};
//evil colleague's code:
namespace std {
//we may specialize std-templates for UDTs...
template<>
struct default_delete<MyUserDefinedType>
{
constexpr default_delete() noexcept = default;
template <class U> default_delete(const default_delete<U>&) noexcept {}
void operator()(T* pt) const { delete pt; }
//sneaky...
void access(MyUserDefinedType& mudt, int i) const
{ mudt.veryPrivateData = i; }
};
}
void somewhere_deep_in_the_code()
{
MyUserDefinedType& myUDT = /*something...*/;
std::default_delete<MyUserDefinedType>().access(myUDT, 42); //tricked you!
}
Friends can do anything to you. Choose them with caution. In this case, I'd really recommend a custom deleter - assuming it makes any sense making the destructor private but providing access to it via the deleter.
Related
In the C++ samples provided by NVidia's TensorRT library, there is a file named common.h that contains definitions of structures used throughout the examples.
Among other things, the file contains the following definitions:
struct InferDeleter
{
template <typename T>
void operator()(T* obj) const
{
delete obj;
}
};
template <typename T>
using SampleUniquePtr = std::unique_ptr<T, InferDeleter>;
The SampleUniquePtr alias is used throughout the code samples to wrap various pointers to interface classes returned by some functions, e.g. SampleUniquePtr<INetworkDefinition>(builder->createNetworkV2(0));
My question is, in what practical aspects are std::unique_ptr and SampleUniquePtr different? The behavior of SampleUniquePtr is pretty much what I would expect from std::unique_ptr, at least now. Could it be for compatibility with old versions of C++?
From the history I see it was for a while
template <typename T>
void InferDeleter::operator()(T* obj) const
{
if (obj)
{
obj->destroy();
}
}
Then they declared destroy() methods deprecated:
Destructors for classes with destroy() methods were previously protected. They are now public, enabling use of smart pointers for these classes. The destroy() methods are deprecated.
Although it is deprecated, it is still not removed and the old ABI InferDeleter should be kept for backward compatibility for applications linked with the old TensorRT. Thus they are using since recently
template <typename T>
void InferDeleter::operator()(T* obj) const
{
delete obj;
}
not removing the struct InferDeleter and using SampleUniquePtr = std::unique_ptr<T, InferDeleter>. But it may be removed in the future. When they remove struct InferDeleter and change using SampleUniquePtr = std::unique_ptr<T>, it will make TensorRT library incompatible with old software.
I don't have the time to scan through the entirety of the linked library, so there is a chance I'm wrong on this count.
But, what you're seeing is probably a default implementation that's used as a fallback for any type that doesn't need special handling.
The Library Implementor always has the option of specializing this function in the situation where they're dealing with a type that actually does need special handling, which is probably pretty common for a library made by Nvidia (and therefore probably meant to interact with the GPU).
class GPUResource {
//...
~GPUResource() noexcept {} //Does NOT perform the special handling, for whatever library-specific reason
};
template<>
void InferDeleter::operator()<GPUResource>(GPUResource * obj) {
performSpecialCleanupOnGPUResource(obj->handle);
delete obj;
}
In practice, this kind of stuff always smells like an anti-pattern (are you sure, Library Implementor, that you couldn't do the cleanup in the destructor of this object??) but if they had good reasons for separating out the logic like this, the way they've defined InferDeleter permits them this kind of flexibility.
The example looks pointless as that is exactly what I expect the default deleter to do.
But maybe this is better (untested):
#include <vector>
struct VectorDeleter
{
template <typename T>
void operator()(std::vector<T*> *v) const
{
for(auto p : *v) delete p;
delete v;
}
};
template <typename V>
using UniquePtrVector = std::unique_ptr<V, VectorDeleter>;
When you have a vector of pointers (to e.g. polymorphic classes) you have to delete the objects the vector points to when the vector is deleted. The VectorDeleter does that before the vector itself is deleted.
I know the general use cases for the friend keyword with regards to encapsulation but one a couple of occasions, I have needed the friend keyword just to "get the job done". These use cases don't make me happy so I'm wondering if there are some alternatives. Here's the first minimal example:
struct Foo{
enum class Bar{
a=1,b=2,c=4
};
// need to tell the compiler of operator| before it gets used
// but it can't be a member function of Foo: so add friend keyword
friend Bar operator|(const Bar& b1, const Bar& b2);
// constructor needs a default value using
// operator| for Bars
Foo( Bar b = Bar::a | Bar::b );
};
// definition of operator|, etc.
Is there any way for the compiler to see the declaration of the operator| for the nested class, inside of interface, before the default values are given at the Foo constructor declaration?
I also sometimes find myself using the friend keyword in defining symmetric operations of nested classes within templates. For example:
template<typename T>
struct A{
struct B{
friend bool operator==(const B& x, const B& y) { return true; }
};
};
The operator== does not require friendship from an encapsulation perspective. But due to operator== not actually being a templated function and the compiler being unable to deduce the types of nested classes within templates, this seems to be the only reasonable "trick" to keep operator== as a free function.
As I said, these choices do work, but I'm wondering if there are better choices/practices out there.
In fact, I would say it's perfectly conventional. While, as mentioned by Evg, hidden friends have special benefits, visible friends are also great to have!
To make this more of an answer, consider for example libstdc++'s implementation of std::unreachable_sentinel_t. This can be returned as the end() of an unbounded "generator range", such as a std::ranges::iota_view{0}. It's very similar to your second example:
struct unreachable_sentinel_t
{
template<weakly_incrementable _It>
friend constexpr bool
operator==(unreachable_sentinel_t, const _It&) noexcept
{ return false; }
};
inline constexpr unreachable_sentinel_t unreachable_sentinel{};
Regular iterators and sentinels are defined as nested classes and also rely on friendship, though their comparison operators typically do need the privileged access. However, even if you could provide an out-of-line definition, an additional benefit of inlining friends in templates is that you don't have to repeat the exact template header, including potentially complicated constraints.
If it helps, in C++ you can think of free functions like these, whether or not they are friends, as being part of the public interface of the classes of their arguments, due to argument-dependent lookup. As such, even if you don't technically need the privilege of friendship, granting it does not break encapsulation.
As long as you're aware of the nuance of hidden friendship, just use friend if it gets the job done!
Often when writing templated code, I find myself needing to store an instance of the template type in a member variable. For example, I might need to cache a value to be used later on. I would like to be able to write my code as:
struct Foo
{
template<typename T>
T member;
template<typename T>
void setMember(T value)
{
member<T> = value;
}
template<typename T>
T getMember()
{
return member<T>;
}
};
Where members are specialized as they are used. My question:
Is such templated member variable possible with current C++ generative coding facilities?
If not, are there any proposals for such a language feature?
If not, are there any technical reasons why such a thing is not possible?
It should be obvious that I do not want to list all possible types (e.g. in a std::variant) as that is not generative programming and would not be possible if the user of the library is not the same as the author.
Edit: I think this somewhat answers my 3rd question from above. The reason being that today's compilers are not able to postpone instantiation of objects to after the whole program has been parsed:
https://stackoverflow.com/a/27709454/3847255
This is possible in the library by combining existing facilities.
The simplest implementation would be
std::unordered_map<std::type_index, std::any>
This is mildly inefficient since it stores each std::type_index object twice (once in the key and once inside each std::any), so a std::unordered_set<std::any> with custom transparent hash and comparator would be more efficient; this would be more work though.
Example.
As you say, the user of the library may not be the same as the author; in particular, the destructor of Foo does not know which types were set, but it must locate those objects and call their destructors, noting that the set of types used may be different between instances of Foo, so this information must be stored in a runtime container within Foo.
If you're wary about the RTTI overhead implied by std::type_index and std::any, we can replace them with lower-level equivalents. For std::type_index you can use a pointer to a static tag variable template instantiation (or any similar facility), and for std::any you can use a type-erased std::unique_ptr<void, void(*)(void*)> where the deleter is a function pointer:
using ErasedPtr = std::unique_ptr<void, void(*)(void*)>;
std::unordered_map<void*, ErasedPtr> member;
struct tag {};
template<class T> inline static tag type_tag;
member.insert_or_assign(&type_tag<T>, ErasedPtr{new T(value), [](void* p) {
delete static_cast<T*>(p);
}});
Example. Note that once you make the deleter of std::unique_ptr a function pointer, it is no longer default-constructible, so we can't use operator[] any more but must use insert_or_assign and find. (Again, we've got the same DRY violation / inefficiency, since the deleter could be used as the key into the map; exploiting this is left as an exercise for the reader.)
Is such templated member variable possible with current C++ generative coding facilities?
No, not exactly what you describe. What is possible is to make the enclosing class a template and use the template parameters to describe the types of the class' members.
template< typename T >
struct Foo
{
T member;
void setMember(T value)
{
member = value;
}
T getMember()
{
return member;
}
};
In C++14 and later, there are variable templates, but you can't make a template non-static data member of a class.
If not, are there any proposals for such a language feature?
Not that I know of.
If not, are there any technical reasons why such a thing is not possible?
The primary reason is that that would make it impossible to define binary representation of the class. As opposed to templates, a class is a type, which means its representation must be fixed, meaning that at any place in the program Foo and Foo::member must mean the same things - same types, same object sizes and binary layout, and so on. A template, on the other hand, is not a type (or, in case of variable templates, is not an object). It becomes one when it is instantiated, and each template instantiation is a separate type (in case of variable templates - object).
Why is operator () of stateless functor not allowed to be static? Stateless lambda objects are convertible to pointers to free functions having the same signature as their operator ().
Stephan T. Lavavej on p. 6 points out that conversion to a function pointer is just an operator FunctionPointer() (cite). But I can't obtain a corresponding pointer to operator () as to non-member function. For functor struct F { void operator () () {} } it seems to be impossible to convert &F::operator () to instance of type using P = void (*)();.
Code:
struct L
{
static
void operator () () const {}
operator auto () const
{
return &L::operator ();
}
};
The error is
overloaded 'operator()' cannot be a static member function
but operator () is not overloaded.
Per standard 13.5/6,
An operator function shall either be a non-static member function or be a non-member function and have
at least one parameter whose type is a class, a reference to a class, an enumeration, or a reference to an
enumeration.
Additionally, in 13.5.4 it is stated that
operator()
shall be a non-static member function with an arbitrary number of parameters. It can have
default arguments. It implements the function call syntax
postfix-expression
(
expression-list
opt
)
where the
postfix-expression
evaluates to a class object and the possibly empty
expression-list
matches
the parameter list of an
operator()
member function of the class. Thus, a call
x(arg1,...)
is interpreted
as
x.operator()(arg1, ...)
for a class object
x
of type
T
I would think that there's no technical reason to forbid this (but not being familiar with the de-facto cross-vendor C++ ABI (Itanium ABI), I can't promise anything).
There's however an evolutional issue about this at https://cplusplus.github.io/EWG/ewg-active.html#88 . It even has the [tiny] mark on it, making it a somewhat "trivial" feature under consideration.
I can't see any technical reason to forbid a static auto operator()( ... ). But it's a special case, so it would complicate the standard to add support for it. And such complication is not necessary, because it's very easy to emulate:
struct L
{
static void func() {}
void operator()() const { func(); }
operator auto () const
{
return &L::func;
}
};
See Johannes' answer for some possibly useful extra info.
Like the others, I don't see a fundamental reason why it is not possible to have a static operator(), for stateless functors or in general.
(EDIT 2020: Just found this proposal http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p1169r0.html)
(UPDATE 2021: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2021/p1169r1.html)
In some cases might conflict, according to other rules, with member/static overloading which is not allowed in C++ (again, not sure why).
struct A{
void f();
static int f(); // compile error
}
So even if it were allowed to have a static operator(), should this be permitted?
struct A{
void operator()();
static int operator()(); // should be a compiler error???
}
Anyway, there is only one true reason to have a static operator() that it is not purely a syntactic reason and it is that objects should be able to call static functions as if they were member functions.
struct A{
static int f():
}
...
A a;
a.f(); // calls A::f() !!!
Specifically, the user of the class A doesn't need to know if a function is implemented as static or as a member.
It can later be upgraded to a member function from a generic point of view.
Leaving that important application to generic programming aside, there is a workaround the leads to a similar syntax that I saw in https://quuxplusone.github.io/blog/2018/03/19/customization-points-for-functions/, and that is to have a static member function called _, a name that doesn't imply any meaning.
struct A{
static int _();
}
...
A::_(); // instead of the more desirable (?) A::() or A::operator()
a._(); // this invokes the static functon _
Instead of the more desirable A::() or A::operator(), (well are they desirable at all? I don't know; something like A() would be really interesting but doens't even follow the syntax of a static function and can be confused with a constructor).
(As I said, the only feature I still miss, regarding this limitation you point out, is that a() cannot automatically delegate to a static version of the operator(), e.g. A::operator().)
In summary, your code could look like this:
struct L{
static void _() {}
auto operator()() const{
return L::_();
}
};
L ell;
ell(); // calls L::_() really.
Not sure what are willing to achieve still.
One can "CRTP" the idea https://godbolt.org/z/74vxsTYxd
#include<utility> // forward
template<class Self>
struct stateless_functor_facade{
template<class... Args>
constexpr decltype(auto) operator()(Args&&... args) const{
return Self::operator_paren(std::forward<Args>(args)...);
}
};
struct square : stateless_functor_facade<square>{
static auto operator_paren(double x){return x*x;}
};
int main(){
square s;
s(5);
}
Starting with C++23 both operator() (P1169) and operator[] (P2589) can be static. There was never really a good reason for the restriction, so it's finally being lifted.
You can also define a Lambda as static by [] static { ... }. If you have a Lambda without captures, you always should define it as static.
Unfortunately, this behavior cannot become the implicit standard without breaking API and ABI compatibility, so the explicit definition is necessary. Backwards compatibility is, as so often, both a blessing and a curse.
i i'm not going to pretend to be an expert at all. however, i was looking into static lamdas or static operator() and theirs an ongoing proposal about it. i was satisfied with what i could understand.
it appears the ideas proposed is grappling with how to design it to not break other code.etc. however it appears their working on a solution. so. mabyeeee one day!
static operator()
Document #: P1169R2
Date: 2021-08-14
Project: Programming Language C++
3 Proposal
The proposal is to just allow the ability to make the call operator a
static member function, instead of requiring it to be a non-static
member function. We have many years of experience with member-less
function objects being useful. Let’s remove the unnecessary object
parameter overhead. There does not seem to be any value provided by
this restriction.
There are other operators that are currently required to be
implemented as non-static member functions - all the unary operators,
assignment, subscripting, conversion functions, and class member
access. We do not believe that being able to declare any of these as
static will have as much value, so we are not pursuing those at this
time. We’re not aware of any use-case for making any of these other
operators static, while the use-case of having stateless function
objects is extremely common.
find full Document here:
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2021/p1169r2.html
It is now possible to have static operator (), after c++23 - go to https://en.cppreference.com/w/cpp/feature_test#Language_features and look for __cpp_static_call_operator. GCC 13 will supports it - https://gcc.gnu.org/projects/cxx-status.html.
Here is an example on Compiler Explorer with gcc trunk.
struct A {
constexpr static int operator() (int x) noexcept { return x - 1; }
constexpr static int operator[] (int x) noexcept { return x - 1; }
};
int main() {
return [](int x) constexpr static noexcept { return x - 1; }( A()( A()[3] ));
}
A simple, a little bit dirty workaround until the relevant committee considers this trivial feature:
Glob operators are syntactically similar to the constructors.
Thus, you can't write a
static MyClass::operator()(...);
It was made simply impossible, because a committee decided so on unclear reasons. I would be so happy if I could talk with one of their members, to ask, what was in their mind as they decided so. Unfortunately, he probably wouldn't understand my question, because he never programmed c++. He only worked on its docs.
Now they need some decades of
debates
consultations
meetings
and considerations
to implement a trivial feature. I suspect the feature may be made available around in c++3x, and on emulated machines it may be even tried out.
Until then, you can try to write:
MyClass::MyClass(...);
In both cases you can call MyClass(...);.
Of course it is useful mainly if MyClass is a singleton. And, I would say it is a hack. Furthermore, it allocates a sizeof(MyClass) on the stack which may be bad in the performance / efficiency side.
Furthermore, this will be in essence a constructor, and constructors can't return anything. But you can avoid this by storing the result in the instance, and then casting it by a cast operator to anything you wish to.
Suppose, we declare the template:
template <class functor, int index>
class MyClass
{
public:
MyClass(){someFunction(index);}
private:
void someFunction(int index)
{
while(index--)
functor();
}
int commonFunction(void)
{
return M_PI;
}
};
Pay attention that the method commonFunction doesn`t depend on the template parameters.
Client uses this template:
MyClass<func1,100> t1;
MyClass<func2,100> t2;
// ...
MyClass<funci,100> ti;
// where i, for example in 1 .. 1000
Will instantiation of the template lead to the duplication of commonFunction in the binary code?
Can a compiler prevent that duplication?
Does C++ standart defines that duplication can be prevented, so every compiler should provide optimization?
Of course this can be easily solved by implementing common functionality for all templates in a base class and moving differences in the templated class, like this:
class baseMyClass
{
int commonFunction(void)
{
return M_PI;
}
};
template <class functor, int index>
class MyClass : private baseMyClass
{
public:
MyClass(){someFunction(index);}
private:
void someFunction(int index)
{
while(index--)
functor();
}
};
But the purpose of my question is to find out:
Does standart defines that in the cases that look like the one I gave optimization should be performed, so we can simply use template and rely on a compiler?
Does standart defines that in the cases that look like the one I gave optimization should be performed, so we can simply use template and rely on a compiler?
No, the Standard does not require by any means that conforming compilers perform such kind of optimization. Code bloating is known to be one of the drawbacks of templates.
This said, since your function does not do anything else than returning a constant, it will probably be inlined, and even in case it will not be inlined, it is possible that the linker will recognize that several identical instantiations of that function have been generated, and merge them all.
However, this behavior is not mandated by the Standard.
The standard does not mandate optimisation on any case. So the answer to your last question is no for any case you can think of. Now, the standard does not prevent optimisation either in this case, and I guess many compilers will be smart enough to do it in this simple case.