I have a class Point
that inherits publicly from another class Vec3
and adds some data members. For example, when asking a spline for it's coordinate some distance along it the extra data returned could be the index of the nearest control point. A requirement is that users that don't care about the extra data in Point
should be able to use it as-if it was a Vec3
.
Point spline(double distance);
Vec3 position = spline(0.4);
This works as intended from the language specification point of view but we've recently incorporated clang-tidy and it gives the following warning:
error: slicing object from type 'Point' to 'Vec3' discards 4 bytes of state [cppcoreguidelines-slicing
Which is true and I want that check enabled in general, but is there some way to tell clang-tidy that slicing a Point
to a Vec3
is ok?
I tried adding operator Vec3()
to Point
in hopes that it would pick that over slicing, but apparently conversion functions are never used when converting to a base class:
[class.conv.fct]
A conversion function is never used to convert a (possibly cv-qualified) object to the (possibly cv-qualified) same object type (or a reference to it), to a (possibly cv-qualified) base class of that type (or a reference to it), or to (possibly cv-qualified) void
Emphasis mine.
A small example:
struct Vec3 {
double x, y, z;
};
struct Point : public Vec3 {
int control;
operator Vec3() { return Vec3 {x, y, z}; } // This does nothing.
};
Point spline(double distance)
{
return Point {distance, 0.0, 0.0, 0};
};
int main()
{
Vec3 point = spline(0.1);
}
main.cpp:7:5: error: conversion function converting 'Point' to its base class 'Vec3' will never be used [clang-diagnostic-warning,-warnings-as-errors]
operator Vec3() { return Vec3 {x, y, z}; } // This does nothing.
^
main.cpp:17:18: error: slicing object from type 'Point' to 'Vec3' discards 4 bytes of state [cppcoreguidelines-slicing,-warnings-as-errors]
Vec3 point = spline(0.1);
This clang-tidy slicing flag is based on C++ Core Guidelines and they link to the exact section. Here you get the reasoning for the guideline as well as an alternative for when slicing is intended:
Alternative
If you mean to slice, define an explicit operation to do so. This saves readers from confusion.
In your example you could something like this:
struct Point : public Vec3 {
int control;
Vec3 copy_as_vec3() { return Vec3 {x, y, z}; }
};