constexpr 'auf verdacht'



  • Hallo,

    ist es moeglich, eine Template-Funktion mit constexpr zu versehen, auch wenn innerhalb dieser Funktion eine 'normale' Funktion aufgerufen wird?

    Beispiel:

    template<typename Derived>
    class base
    {
    public:
        constexpr int width()
        {
            return static_cast<Derived&>(*this).width();
        }
    };
    
    class dynamic
    {
    public:
        int width()
        {
            return m_width;
        }
    
    private:
        int m_width;
    };
    
    template<int Width>
    class fixed
    {
    public:
        constexpr int width()
        {
            return Width;
        }
    };
    
    int main()
    {
        base<fixed<4>> a;
        base<dynamic> b;
    
        constexpr int width_a = a.width(); // base::width ist constexpr
        int width_b = b.width(); // Wird hier das constexpr von base::width ignoriert? Kompilieren tut es jedenfalls.
    }
    


  • kaos schrieb:

    ist es moeglich, eine Template-Funktion mit constexpr zu versehen, auch wenn innerhalb dieser Funktion eine 'normale' Funktion aufgerufen wird?

    constexpr bedeutet "das hier liefert eine Compilezeit-Konstante, wenn es in einem Compilezeit-konstanten Kontext aufgerufen wird." Bei normalen Funktionen bedeutet das, dass eine constexpr-Funktion keine constexpr-Funktion mehr ist, wenn du ihr Argumente übergibst, die nicht constexpr sind. Aufgerufene Funktionen müssen natürlich constexpr sein, sonst ist der compilezeit-konstante Kontext nie gegeben.
    Bei einem Funktionstemplate kann der Compiler beim ersten pass nicht sehen, ob die aufgerufenen Funktionen constexpr sind. Bei der Instantiierung guckt er dann, ob der Kontext compilezeit-Konstant ist - könnte ja sein dass das für bestimmte Template-Argumente tatsächlich der Fall ist, wie du gezeigt hast.



  • Der Beispiel-Code war natuerlich falsch.
    Richtig:

    template<typename Derived>
    class base
    {
    public:
        constexpr int width()
        {
            return static_cast<Derived&>(*this).width();
        }
    };
    
    class dynamic : public base<dynamic>
    {
    public:
        int width()
        {
            return m_width;
        }
    
    private:
        int m_width;
    };
    
    template<int Width>
    class fixed : public base<fixed<Width>>
    {
    public:
        constexpr int width()
        {
            return Width;
        }
    };
    

    Bei der Instantiierung guckt er dann, ob der Kontext compilezeit-Konstant ist - könnte ja sein dass das für bestimmte Template-Argumente tatsächlich der Fall ist, wie du gezeigt hast.

    Heisst das, das gezeigte Beispiel is legitim?


  • Mod

    kaos schrieb:

    static_cast<Derived&>(*this)

    Ist niemals ein konstanter Ausdruck; this kann in einem konstanten Ausdruck nur dazu verwendet werden, um auf Member zuzugreifen.


Anmelden zum Antworten