2016-09-13 10 views
9

Belirli bir şablon türünün argümanlarını alan bir işlev var;Bir const olmayan şablon argüman türünün bir const'e dolaylı olarak dönüştürülmesine izin vermenin kanonik bir yolu var mı?

#include <type_traits> 

template <typename T> 
struct foo 
{ 
    // default constructor 
    foo() { } 

    // simple copy constructor that can construct a foo<T> from a foo<T> 
    // or foo<const T> 
    foo(const foo<typename std::remove_const<T>::type> &) { } 
}; 

İşlevsel olarak, foo bu soruya alakalı olmayan başka eklenti işlevselliği ile, bir shared_ptr<T> benzer şekilde davranır: gibi basitleştirilmiş versiyonu görünebilir. Fonksiyonun semantiği, bir foo<const T> içinde almayı tercih ettiğini dikte eder. foo<const T>foo<T> gelen dolaylı constructible, bu yüzden aşağıdaki gibi bir şey yapabilmek istiyorum:

template <typename T> 
void bar(foo<const T> f) { } 

int main() 
{ 
    bar(foo<const int>()); // fine 
    bar(foo<int>());  // compile error 
} 

almak bar için eşleşen aşırı yükler olduğundan bu başarısız bir foo<int> (a foo<const int> dolaylı olabilir rağmen bir foo<int> inşa, şablon örnekleme uyum içinde aşırı yük çözünürlüğü daha sıkı görünüyor.

bunu yapmanın kurallı bir yolu var mı? Benalır bar() için ikinci aşırı katılabileceği de biliyoruz 0 ve bar(foo<const T>)'a elle gönderir, ancak mümkünse çoğaltmayı önlemek isterim.

+0

İşleri ince (bcc32) ancak C++ 14 ('types' const T 've' int 'ile uyumlu olmayan cv-qualifiers') kullanarak ideone.com'da değil. –

+0

Sadece ben mi yoksa tersini mi yaptın? Copy c-tor 'remove_const' kullanır ve açıklamanız ve' bar 'sözcüğünü kullanan kod ** **' const 'ekleyen bir durum hakkındadır. –

+0

@YehezkelB .: Buradaki fikir, 'foo 'foo'nun ' yapısından yapılabilmesidir, bu yüzden kurucunun argümanında 'const' öğesini kaldırmanız gerekir. Ben * düşünüyorum * yazılı olarak doğru. –

cevap

5

nedenidir. Bu durumda, foo<int>, foo<const T> ile eşleşmeyecek ve derleyici, T'un ne olduğunu anlayamayacaktır.

template <typename T> // T might be foo<int> 
void bar(T f) { } 

Yoksa isterseniz derleyici anlamak sağlayabilirsiniz: Ne yapabilirsiniz

int main() 
{ 
    bar(foo<const int>()); // fine 
    bar<int>(foo<int>()); // also fine 
} 

derleyici türlü yapmasına izin vermek: Doğrudan türünü belirtmek kontrol etmek kendiniz deneyebilirsiniz Kat olmadan iç T:

template <typename T> // can deduce T as const int 
void bar(foo<T> f) { } 

gerçekten, size sınıf bir yardımcı işlev eklemek isteyebilirsiniz (hatta genel kodda) constness zorlamak istiyorsanız, böyle bir şey: Eğer genel bir işlevini kullandığınızda Yani, gönderebilir

foo<const T> as_const() const { return *this; } 

sınıfınızın bir const sürümüdür: my öncesi C++ 11 derleyici gösterildiği gibi benim için

bar<int>(foo<int>{}.as_const()); 
+0

Şablon işlevini çağırdığım bağlamda ortaya çıkıyor, açık bir şekilde şablon argümanı türünü belirtmek uygun, bu yüzden benim uygulama için de çalışır. –

+0

Şablon argümanı türünü belirtirseniz, işlevlerinizi dağıtma yerine, sınıfınızın foo'sunun ne ile oluşturulduğunu almak için bir şablon takma adı tanımlayabilirsiniz. –

6

Şablonlar dönüştürmeye izin vermiyor!

Eğer yazarken:

template <typename T> 
void bar(foo<const T> f) { } 

bar herhangi T için, bir foo<const T> kabul eder. Başka hiçbir şey kabul etmez. foo<int>'un foo<const int>'a dönüştürülebilmesi önemli değildir, bu dönüştürme hiçbir zaman dikkate alınmaz. Tam dur. Eğer const olarak f alınan tedavi etmek istiyorsanız

, koşullu o const yapabilirsiniz: Örtülü dönüşüm şablon argümanı düşüldükten sonra uygulamak olduğu için kod çalışmıyor

// convert this version 
template <class T> foo<T const> make_const_f(foo<T> const& rhs) { return {rhs}; }  
// pass this version through 
template <class T> foo<T const>& make_const_f(foo<T const>& rhs) { return rhs; } 

template <typename T> 
void bar(foo<T> f) { 
    auto&& const_f = make_const_f(f); 

    // if T was const, const_f is a reference to f 
    // if T wasn't const, const_f is a new object of type foo<T const> 
} 
+0

'std' için 'as_const' önerilmekle birlikte, farklı semantiklerle özgür bir işlev oluşturmak kötü bir fikir gibi görünüyor. – Yakk

+0

@Yakk Evet, adlandırma zor. – Barry

+2

Programlamada iki zor şey var. Adlandırma, önbelleğe alma ve tek tek hatalar. – Yakk

İlgili konular