4 ms·
There's one type for which I will almost always use a C-style cast rather than a C++ cast: void foo(int unused) { (void)unused; } or alternatively, in
by dataflow 5y ago
There's one type for which I will almost always use a C-style cast rather than a C++ cast:
void foo(int unused) {
(void)unused;
}
or alternatively, in situations like:
template<class T>
typename std::enable_if<((void)sizeof(T), true)>::type foo(T &&);
Edit:
Also note that static_cast isn't quite like a function call, because it does something a function call does not, which is to extend the lifetime of the temporary it's operating on.
To see the difference, try replacing static_cast here with static_cast_:
#include <stdio.h>
struct B { };
struct S : B {
~S() { printf("~S(): %p\n", static_cast<void *>(this)); }
S() { printf("S(): %p\n", static_cast<void *>(this)); }
S(const S &) { printf("S(const S &): %p\n", static_cast<void *>(this)); }
S &operator =(const S &) { printf("S &operator =(const S &): %p\n", static_cast<void *>(this)); return *this; }
};
static S foo() { return S(); }
template<class To, class From>
To static_cast_(const From &v) { return static_cast<To>(v); }
int main(int argc, char *argv[]) {
(void)argc;
(void)argv;
const B &b = static_cast<const B &>(foo());
printf("Middle: %p\n", static_cast<const void *>(&b));
(void)b;
}
The compiler "sees through" the cast to extend the lifetime of the object returned by foo(), which produces different output.
- steerablesafe 5y agoDo you `enable_if` on completeness of a type? I would recommend against it, it's prone to ODR violations.
- dataflow 5y agoNot in functions I believe (that was just for illustration), but in other occasions, yes, it's happened - sometimes it's necessary with template metaprogramming.
- steerablesafe 5y agoI'm curious about a valid use case there. If you have a minimal example, or a link to some public code, I would love to see it. There is a reason to be cautious there, the standard library also tends to static_assert on completeness instead of trying to be SFINAE-friendly.
- dataflow 5y agoI never said I make it SFINAE-friendly! I just said I use enable_if. Sometimes I use enable_if because it's handier for me than an alternative like static_assert, that's all. I actually don't recall if I've ever needed this in an SFINAE context before. That said, here's one possible place where it might make sense with SFINAE. Note that I haven't fully thought this through, I'm just doing this off the top of my head right now, so it's possible I'll miss something: #include <iterator> #include <type_traits> namespace stdext { template<class> class checked_array_iterator; } // Forward-declare MSVC-specific type namespace bar { namespace { template<class T> std::enable_if_t<(std::is_same_v<stdext::checked_array_iterator<typename std::iterator_traits<typename T::foo_iterator>::value_type *>, typename T::foo_iterator> && ((void)sizeof(typename T::foo_iterator), true))> debug_verify(const T &obj, ...) { // extra sanity checks against obj.get_foo_iterator() } template<class T> std::enable_if_t<!(std::is_same_v<stdext::checked_array_iterator<typename std::iterator_traits<typename T::foo_iterator>::value_type *>, typename T::foo_iterator> && ((void)sizeof(typename T::foo_iterator), true))> debug_verify(const T &) { // nothing to do } } class S { auto foo() { bar::debug_verify(this->field1); bar::debug_verify(this->field2); } // ... }; } Note that I'm by no means claiming this is the only way to do this. (Edit: Removed a final comment about turning it into a is_checked_array_iterator trait - messed up that part.)
- steerablesafe 5y agoI'm not saying that you are making things SFINAE friendly. I'm just curious about a use case you have where you use enable_if on completeness. Not asking for making up a use case where you SFINAE on completeness. > which would avoid putting (void)sizeof(It) directly inside an SFINAE context. I'm just saying you could do it this way without violating ODR or other stuff I think (unless I'm missing something). Putting it in an alias template doesn't sidestep putting it in an SFINAE context. The detection idiom works because it can still be an SFINAE context.
- dataflow 5y ago> I'm not saying that you are making things SFINAE friendly. I thought that's why you wrote "static_assert instead of trying to be SFINAE-friendly" then, but okay. > I'm just curious about a use case you have where you use enable_if on completeness. That's all you want, without SFINAE? How about something like this: template<class T> class S { std::unique_ptr<unsigned char[]> buf; public: template<std::enable_if_t<((void)sizeof(T), true), bool> = false> explicit S(unsigned char *p, size_t n) : buf(p) { assert(sizeof(T) <= n); } // ... }; NDEBUG optimizes out the completeness check that's implicit in the assert() call, but you'd still want to ensure completeness even without the assert, so you write it explicitly. Obviously you can use static_assert here too, but merely using enable_if in lieu of that doesn't suddenly get you an ODR violation. EDIT: Come to think of it, actually I think static_assert here is less safe than enable_if and increases the risk of an ODR violation. Check out the difference in behavior here when you uncomment the enable_if_t: #include <type_traits> class X; template<class T> class S { public: // template<std::enable_if_t<((void)sizeof(T), true), bool> = false> explicit S(unsigned char *) { static_assert(sizeof(T) > 0, "oops"); } }; static S<X> s(nullptr); int main() { } class X { };
- Leherenn 5y agoIn the first case you can simply omit "unused", but I can see value in marking it explicitly.
- dataflow 5y agoIt's not just documentation btw. Sometimes the value is "used", but only in conditionally compiled code. Like assert(!unused). Then you need the variable there, but want to tell the compiler not to bug you about it being unused.
- grumbel 5y agoOr just drop the warning completely with `-Wno-unused-parameter`, as it just creates a lot of noise, makes the code uglier and never catches any bugs. When dealing with virtual functions or callbacks, having some unused function parameter is just far to common to be worth warning about.
- dataflow 5y ago> it just creates a lot of noise, makes the code uglier and never catches any bugs It definitely does catch bugs for me. It's admittedly not all that frequent, but it's quite useful when it does.
- deleted 5y ago[deleted]
- pjmlp 5y agoI never got that, just don't name the parameter, no need for casting tricks.