Search code examples
c++clang-tidy

How do I tell clang-tidy that slicing a particular class is ok?


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

class.conv.fct

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);

Solution

  • 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}; }
    };