C ++ 'ın ikinci bir şablon bağımsız değişkenini tahmin etmesini nasıl önleyebilirim?


26

İçinde bir yerde, aşağıdaki kodu olan bir C ++ kitaplığı ( strf ) kullanıyorum :

namespace strf {
template <typename ForwardIt>
inline auto range(ForwardIt begin, ForwardIt end) { /* ... */ }

template <typename Range, typename CharT>
inline auto range(const Range& range, const CharT* sep) { /* ... */ }
}

Şimdi, kodumda kullanmak istiyorum strf::range<const char*>(some_char_ptr, some_char_ptr + some_length). Ancak bunu yaparsam, aşağıdaki hatayı alıyorum (CUDA 10.1'in NVCC'sinde):

error: more than one instance of overloaded function "strf::range" matches the argument list:
            function template "auto strf::range(ForwardIt, ForwardIt)"
            function template "auto strf::range(const Range &, const CharT *)"
            argument types are: (util::constexpr_string::const_iterator, util::constexpr_string::const_iterator)

Kütüphane kod muhtemelen bu (örn kullanmaktan kaçınmak için değiştirilebilir:

inline auto range(const typename std::enable_if<not std::is_pointer<typename std::remove_cv<Range>::type>::value, Range &>::type range, const CharT* sep)

sağlamak Rangeiçin bir işaretçi değildir); ama şu anda bu değişikliği yapamam. Bunun yerine, bir şekilde derleyiciye gerçekten bir tane şablon argümanı olduğunu, bir tanesi belirtilmediğini ve diğeri çıkartıldığını gerçekten belirtmek istiyorum.

Bunu yapabilir miyim?

C ++ 11 ve C ++ 14 için cevapları takdir eder; Kesinti rehberlerini içeren C ++ 17 cevapları daha az önemlidir, ancak varsa, lütfen gönderin (gelecekteki NVCC sürümleri için ...)


Güncelleme: strf kütüphanesinin kendisi bu durumu atlatmak için güncellendi, ancak soru sorulduğu gibi duruyor.


1
Ben ince bir sarar char*ama biri değil bir çözüm değil özel bir yineleyici geçen tahmin ediyorum ?
Konrad Rudolph

1
@KonradRudolph: Bu bir çözüm, ancak soruma cevap vermiyor. Aslında zaten başka bir çözüm var (/*...*/ ne özel), ama burada yüksek yol almak istiyorum.
einpoklum

1
Bu durumda (tahmin edilen) cevabım maalesef “yapılamaz”. Adil olmak gerekirse, önerilen geçici çözümümü kendi kodumda kabul edeceğinden emin değilim.
Konrad Rudolph

Sadece açıklığa kavuşturmak için: Genel bir çözüm ister misiniz, bu her zaman şablon aşırı yükleri ile bir veya iki parametreli bir çağrıyı birbirinden ayırmak için işe yarar mı yoksa sadece bu duruma özel bir çözüm mü istiyorsunuz?
Ceviz

@ ceviz: Genel çözüm daha iyi olurdu; benim özel senaryom çoğunlukla sorun için motivasyon.
einpoklum

Yanıtlar:


16
template<typename T>
inline constexpr auto range1_ptr = strf::range<T>;

template<typename T>
inline decltype(auto) range1(T begin, T end) {
    return range1_ptr<T>(begin, end);
}

Sonra range1yerine arayın strf::range.

range1_ptr<T>(...)her zaman bir şablon argümanı alarak şablonu açıkça çağırmak için kullanılabilir, ancak bağımsız değişkenlerden herhangi bir kesinti yapmaz. range1orijinal strf::rangeşablondan kesinti çoğaltır .

Bu çalışır, çünkü [temp.deduct.funcaddr] / 1 , hedef türü dönüştürülmeyen bir fonksiyonun adresini alırken şablon argümanı kesintisinin, her aday fonksiyon şablonunda varsayımsal bir çağrının parametre ve argüman listeleriymiş gibi yapıldığını söylüyor. boş. Dolayısıyla, ikinci şablon argümanı, iki şablon parametresi ile ikinci aşırı yük için çıkartılamaz. Kalan tek aday, fonksiyon işaretçisinin hedefi olarak seçilecek ilk aşırı yüklenmedir.

Yalnızca bir bağımsız değişkeni olan geçerli bir şablon kimliğinin oluşturulabileceği ikinci bir aday işlev şablonu olmadığı sürece, range1_ptrher zaman bir bağımsız değişkeni kesin olarak alan işlev şablonunu çağırmak için her zaman kullanılabilir. Aksi takdirde, range1_ptrbelirsizliği nedeniyle somutlaştırılması hata verir.


Hakkında bir belirsizlik olmayacak strf::range<T>mı?
einpoklum

1
@einpoklum GCC ve Clang üzerinde iyi derler. Standardı kontrol etmedim, ancak bunun belirsiz olması gerekiyorsa şaşırırdım.
Ceviz

Belki fonksiyon adını pretty_please_with_sugar_on_top()? ... C ++ bazen çok garip olabilir ...
einpoklum

Kabul edilen cevabı
çözmeyi başardın

11

Peki ya bir using?

using tfp = void(*)(char const *, char const *);

tfp x = &strf::range;

char const * a = "abcd";

(*x)(a, a+2);

Ve bu derleniyor mu? İkinci satır özellikle şüpheli görünüyor.
einpoklum

@einpoklum - komik, değil mi?
max66

@einpoklum - ne yazık ki genel bir çözüm değil; Bu durumda çalışır (eğer yanlış değilsem) sadece ilk range()sürüm ile uyumludur tpf; diğer durum farklı olabilir.
max66

@ einpoklum - ikinci satırda template parametresini ( tfp x = &strf::range<char const *>;) de açıklayabilirsiniz ; bu şekilde sanırım
cevizinkine

0

Bir çözüm

1) her şeyden önce, ikinci argüman için tür belirtmelisiniz, örn. (char *)(some_char_ptr + some_length)

2) consther ikisi için kullanmayın , bu iyi çalışır:

strf::range((char *)some_char_ptr, (char *)(some_char_ptr + some_length));

Soldaki VEYA sağdaki (char *)ile değiştirmeyi deneyebilirsiniz (const char *), yine de çalışır.


Argümanlar constverilere işaret ediyorsa bu oldukça çirkin bir durumdur .
aschepler

1. Orada değil ikinci argüman. Tek argümanlı şablonu istiyorum. 2. İlginç bir kesmek! İlk öneri için -1 ve ikinci için +1 :-P
einpoklum
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.