2013-07-19 32 views
24

operator*= ve operator* aşırı yüklü çoğaltma ile basit bir Wrapper sınıfı düşünün. "Eski stil" operatör aşırı yüklemesi için, operator*= açısından operator* tanımlanabilir, ve Boost.Operators gibi kütüphaneler bile vardır ve @DanielFrey tarafından sizin için en uygun olan, df.operators modern kazanımı vardır. Bununla birlikte, yeni C++ 11 constexpr'u kullanarak derleme zamanı hesaplamaları için, bu kolaylık ortadan kalkar. İkincisi onun (örtük) sol argüman değiştirir çünkü constexpr operator*operator*= diyemezsin. Dahası, orada no overloading on constexpr, yani bir aşırı yük çözünürlük belirsizlik mevcut operator* sonuçlarına fazladan constexpr operator* ekledi.Constexpr operatör aşırı yükleme yapmak için yönergeler?

Benim şu anki yaklaşımdır:

#include <iostream> 

struct Wrap 
{ 
    int value;  

    Wrap& operator*=(Wrap const& rhs) 
    { value *= rhs.value; return *this; } 

    // need to comment this function because of overloading ambiguity with the constexpr version 
    // friend Wrap operator*(Wrap const& lhs, Wrap const& rhs) 
    // { return Wrap { lhs } *= rhs; }  

    friend constexpr Wrap operator*(Wrap const& lhs, Wrap const& rhs) 
    { return { lhs.value * rhs.value }; } 
}; 

constexpr Wrap factorial(int n) 
{ 
    return n? factorial(n - 1) * Wrap { n } : Wrap { 1 };  
} 

// want to be able to statically initialize these arrays 
struct Hold 
{ 
    static constexpr Wrap Int[] = { factorial(0), factorial(1), factorial(2), factorial(3) }; 
}; 

int main() 
{ 
    std::cout << Hold::Int[3].value << "\n"; // 6 
    auto w = Wrap { 2 }; 
    w *= Wrap { 3 }; 
    std::cout << w.value << "\n"; // 6 
} 

Live output here. Bu Benim sorunlar şunlardır:

  • hem operator*= ve operator* yılında çarpma mantığının çoğaltılması, yerine operator* dolayısıyla operator*=
  • cinsinden ifade ediliyor, Boost.Operators artık pek yazmak için klişe azaltmak için çalışır diğer aritmetik operatörler

Soru: bir çalışma zamanı operator*= ve karışık çalışma zamanı hem de sahip olan, bu önerilen C++ 11 yolu/derleme zamanı 01.237.? C++ 14 burada herhangi bir şeyi değiştirir. mantık çoğaltmayı azaltmak?

GÜNCELLEME: @AndyProwl tarafından cevap deyimsel olarak kabul etmiş, ancak @DyP önerisi gereğince, içinde olduğu C++ 11 tek fazladan atama ve karşı-sezgisel tarzı pahasına mantık tekrarını azaltabilir

// define operator*= in terms of operator* 
    Wrap& operator*=(Wrap const& rhs) 
    { *this = *this * rhs; return *this; } 
+0

o 'constexpr' olabilir eğer bir 'normal' aşırı için ne faydası var? IIRC 'constexpr' incelikle olmayan 'constexpr' bağlamda execution_ _runtime için düşer. – sehe

+1

@se, bir constexpr operatörüne sahip olamazsınız * = ', ve' constexpr operatörü * 'bunu çağıramaz ve bunun yerine alanları ayıklama mantığını çoğaltmanız gerekir. – TemplateRex

+1

Ah, asıl sorunuzu görmeye başladım. O var *** değil *** (onları gerek yok!) Ama olmayan 'constexpr' aşırı yükleri olması konusunda oldukça '* =' 'constexpr' olamaz çünkü kod paylaşmak mümkün değil varlık hakkında.İyi bir şey, zaten iyi niyetle + 1ediyorum :) – sehe

cevap

17

(geçici bir çözüm olarak, DyP's suggestion benim için kabul edilebilir olsa da) C++ 11 için bir deyimsel çözüm olabilir. C++ 14 ancak olarak

, burada constexpr does not imply const (C++ 14 Standart Taslak n3690 Ek C.3.1 bakınız), sadece constexpr hem operator *= ve operator * tanımlar ve eski açısından ikinci tanımlayabilir Her zamanki gibi: İşte

struct Wrap 
{ 
    int value;  

    constexpr Wrap& operator *= (Wrap const& rhs) 
    { value *= rhs.value; return *this; } 

    friend constexpr Wrap operator * (Wrap const& lhs, Wrap const& rhs) 
    { return Wrap(lhs) *= rhs; }  
}; 

yukarıdaki program Clang üzerinde -std=c++1y ile derlenmiş olan bir live example, - ne yazık ki, GCC henüz bu kuralı uygulamak için görünmüyor.

+0

DyP'nin bir ödevin maliyetine bağımlılığı tersine çevirme önerisi hakkında ne düşünüyorsunuz? – TemplateRex

+5

@TemplateRex: Evet, bunu kendim düşündüm, ama bir çözüm olarak göndermedim çünkü standart uygulamaya karşı çıkacaktı. Etkinleştirici değişiklik C++ 14 için hazır olduğunda bir yönergesini geri almak uygunsuz IMO olur. Ancak, bir C++ 11 geçici çözüm olarak kabul edilebilir olmalıdır. Dürüst olmak gerekirse, performansın burada bir sorun olacağını düşünmüyorum - Ben derleyici uzmanı değilim, ancak optimizatörün bu gibi basit işlevler için yoğun bir inline olmasını beklerdim. Ayrıca, erken optimizasyondan uzak durmaya çalışıyorum ve sadece performans varsayımlarından dolayı bir tasarımı reddetmekten kaçınıyorum. –

+0

"Constexpr" artık "const" i ima etmiyor, şaşırıyorum ** neden ** çalışıyor: 'operator * =' hem çok satırlı, hem de mutasyon yapıyor, ama derleme sırasında çağrılıyor. Her iki kısıtlama da * C++ 14'te kaldırıldı mı? Çalışan bir kağıt teklifin var mı? – TemplateRex

İlgili konular