Neden işlev şablonu kısmen özelleştirilemez?


89

Dil belirtiminin kısmen yasakladığını biliyorum , işlev şablonunun uzmanlaşmasını .

Bunu neden yasakladığının gerekçesini bilmek isterim? Yararlı değiller mi?

template<typename T, typename U> void f() {}   //allowed!
template<> void f<int, char>()            {}   //allowed!
template<typename T> void f<char, T>()    {}   //not allowed!
template<typename T> void f<T, int>()     {}   //not allowed!

İçin template<typename T, typename U> void f(T t, U u) {}de template<> void f(int t, char u) {}izin verilir.
çizgi

10
Soru "benzer bir hedefe nasıl ulaşabilirim" değil, "bu davranışın arkasındaki mantık nedir? Komite, işlev şablonu kısmi uzmanlaşmayı yasaklamak için bir nedene sahip olmalıdır. Şimdiye kadar "en yakın" açıklama, Georgy tarafından yayınlanan ve aşırı yükler mevcut olduğunda işlev şablonu kısmi uzmanlaşmasının potansiyel "risklerine" işaret eden bağlantıdır. Ancak, ben daha bu .. orada olduğunu varsayalım, bu yüzden bu özelliği korusun için bir neden olduğunu sanmıyorum
bartgol

Yanıtlar:


59

C ++ 0x'de değiştirilen AFAIK.

Sanırım bu sadece bir gözetimden ibaretti (kısmi uzmanlaşma etkisini her zaman daha ayrıntılı kodla, işlevi staticbir sınıfın üyesi olarak yerleştirerek elde edebileceğinizi düşünürsek ).

Varsa, ilgili DR'ye (Kusur Raporu) bakabilirsiniz.

DÜZENLEME : Bunu kontrol ederek, başkalarının da buna inandığını görüyorum, ancak taslak standartta hiç kimse böyle bir destek bulamıyor. Bu SO iş parçacığı , işlev şablonlarının kısmi uzmanlaşmasının C ++ 0x'de desteklenmediğini gösteriyor gibi görünüyor .

DÜZENLEME 2 : "işlevi staticbir sınıfın üyesi olarak yerleştirmekle" ne demek istediğime dair sadece bir örnek :

#include <iostream>
using namespace std;

// template<typename T, typename U> void f() {}   //allowed!
// template<> void f<int, char>()            {}   //allowed!
// template<typename T> void f<char, T>()    {}   //not allowed!
// template<typename T> void f<T, int>()     {}   //not allowed!

void say( char const s[] ) { std::cout << s << std::endl; }

namespace detail {
    template< class T, class U >
    struct F {
        static void impl() { say( "1. primary template" ); }
    };

    template<>
    struct F<int, char> {
        static void impl() { say( "2. <int, char> explicit specialization" ); }
    };

    template< class T >
    struct F< char, T > {
        static void impl() { say( "3. <char, T> partial specialization" ); }
    };

    template< class T >
    struct F< T, int > {
        static void impl() { say( "4. <T, int> partial specialization" ); }
    };
}  // namespace detail

template< class T, class U >
void f() { detail::F<T, U>::impl(); }    

int main() {
    f<char const*, double>();       // 1
    f<int, char>();                 // 2
    f<char, double>();              // 3
    f<double, int>();               // 4
}

n3225'te standart var mı? Hızlı bir arama yaptım ama bulamadım: /
Matthieu M.

1
ah üzgünüm ... bir kelime eksikti. Belgeye sahibim, ancak belirli bir paragrafı bulamadım . Düzenlemeniz verilmiş olsa da, sanırım sadece içinde olmadığı için :)
Matthieu M.

3
Bu, C ++ 0x'de değiştirilmez. Ayrıca faydasından da şüpheliyim. Her zaman şablonu aşırı yükleyebilir ve kısmi sıralamayı kullanabilirsiniz .
Johannes Schaub -

1
Geç güncelleme: sekiz yıl sonra C ++ 17'de bile değişmedi ve C ++ 20'ye girmiyor gibi görünüyor. Yine de herhangi bir sebep göremiyorum ...
Aconcagua

Sanırım bu, konseptin en kapsamlı uygulamasıdır
Victor

19

Pekala, gerçekten kısmi işlev / yöntem uzmanlığı yapamazsınız, ancak aşırı yükleme yapabilirsiniz.

template <typename T, typename U>
T fun(U pObj){...}

// acts like partial specialization <T, int> AFAIK 
// (based on Modern C++ Design by Alexandrescu)
template <typename T>
T fun(int pObj){...} 

Bu yol ama seni tatmin edip etmediğini bilmiyorum.


2
Vay be, zihnim şablonlarla doluydu öyle ki, işlerin ne kadar basit olabileceğini gerçekten unuttum :)
Johannes

2
Maalesef, işlevi kısmen uzmanlaştırdıktan sonra değişken argümanlar iletmek istediğinizde durum böyle değil .. :(
Gwangmu Lee

Değişken şablonlar iletmenin ne anlama geldiğinden emin değilim, bu yüzden kısmi bir uzmanlıktan ne kadar farklı olduğunu bilmek istiyorum. Lütfen daha fazla ayrıntı verebilir misiniz?
beginpluses

Ya tüm integral ve kayan tipler için sadece iki fonksiyon istiyorsanız?
Dmitriy Dokshin

15

Genel olarak, aşırı yükleme ile ilgili sorunlar nedeniyle işlev şablonlarının hiç özelleştirilmesi önerilmez. İşte C / C ++ Users Journal'dan güzel bir makale: http://www.gotw.ca/publications/mill17.htm

Ve sorunuza dürüst bir cevap içerir:

Birincisi, onları kısmen uzmanlaştıramazsınız - büyük ölçüde sadece dil yapamayacağınızı söylediği için.


3
Makale bir kez bahsedilmesinin yanı sıra kısmi uzmanlaşma hakkında değil.
Euri Pinhollow

11

Sınıfları kısmen özelleştirebildiğiniz için bir functor kullanabilirsiniz:

#include <iostream>

template < typename dtype , int k > struct fun
{
 int operator()()
 {
  return k ;
 }
} ;

template < typename dtype > struct fun < dtype , 0 >
{
 int operator()()
 {
  return 42 ;
 }
} ;

int main ( int argc , char * argv[] )
{
 std::cout << fun<float,5>()() << std::endl ;
 std::cout << fun<float,0>()() << std::endl ;
}

1
Daha sonra, çirkin ()()sözdiziminden kurtularak aramaları yapmak için tek bir işlev şablonu kullanabilirsiniz .
tmr232
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.