Pertanyaan “Constexpr if” vs “if” dengan optimisasi - mengapa "constexpr" dibutuhkan?


C ++ 1z akan memperkenalkan "constexpr if" - dan jika itu akan membuat salah satu cabang dihapus, berdasarkan kondisinya. Tampaknya masuk akal dan bermanfaat.

Namun, apakah itu tidak mungkin dilakukan tanpa kata kunci constexpr? Saya pikir bahwa selama kompilasi, kompilator harus tahu kondisi yang lebih dikenal selama waktu kompilasi atau tidak. Jika ya, bahkan tingkat optimasi yang paling dasar pun harus menghapus cabang yang tidak perlu.

Misalnya (lihat di Godbolt: https://godbolt.org/g/IpY5y5):

int test() {
    const bool condition = true;
    if (condition) {
      return 0;
    } else {
      // optimized out even without "constexpr if"
      return 1;
    }
}

Penjelajah Godbolt menunjukkan, bahwa bahkan gcc-4.4.7 dengan -O0 tidak mengkompilasi "return 1", sehingga mencapai apa yang dijanjikan dengan constexpr jika. Tentunya, compiler lama seperti itu tidak akan bisa melakukannya ketika kondisi adalah hasil dari fungsi constexpr, tetapi kenyataannya tetap: kompilator modern tahu apakah kondisi itu constexpr atau tidak dan tidak perlu saya untuk mengatakannya secara eksplisit.

Jadi pertanyaannya adalah:

Mengapa "constexpr" dibutuhkan dalam "constexpr if"?


32
2017-12-05 10:59


asal


Jawaban:


Ini mudah dijelaskan melalui sebuah contoh. Mempertimbangkan

struct Cat { void meow() { } };
struct Dog { void bark() { } };

dan

template <typename T>
void pet(T x)
{
    if(std::is_same<T, Cat>{}){ x.meow(); }
    else if(std::is_same<T, Dog>{}){ x.bark(); }
}

Meminjam

pet(Cat{});
pet(Dog{});

akan memicu kesalahan kompilasi (contoh wandbox), karena kedua cabang dari if Pernyataan harus dibentuk dengan baik.

prog.cc:10:40: error: no member named 'bark' in 'Cat'
    else if(std::is_same<T, Dog>{}){ x.bark(); }
                                     ~ ^
prog.cc:15:5: note: in instantiation of function template specialization 'pet<Cat>' requested here
    pet(Cat{});
    ^
prog.cc:9:35: error: no member named 'meow' in 'Dog'
    if(std::is_same<T, Cat>{}){ x.meow(); }
                                ~ ^
prog.cc:16:5: note: in instantiation of function template specialization 'pet<Dog>' requested here
    pet(Dog{});
    ^

Berubah pet menggunakan if constexpr

template <typename T>
void pet(T x)
{
    if constexpr(std::is_same<T, Cat>{}){ x.meow(); }
    else if constexpr(std::is_same<T, Dog>{}){ x.bark(); }
}

hanya membutuhkan cabang-cabang untuk menjadi parseable - hanya cabang yang sesuai dengan kondisi yang perlu dibentuk dengan baik (contoh wandbox).

Cuplikan

pet(Cat{});
pet(Dog{});

akan dikompilasi dan berfungsi seperti yang diharapkan.


41
2017-12-05 11:07