Şablonları kullanarak bir işlevi aşırı yükleme


34

Şablonları kullanarak bir işlev tanımlamak çalışıyorum ve typename int veya anEnum (tanımladığım belirli bir numaralandırma) olmasını istiyorum. Aşağıdaki denedim ama başarısız oldu:

template <int | anEnum T> // or <int T, anEnum T> or <int, anEnum T>
bool isFunction(const T &aVariable){}

Yapmaya çalıştığım, aşırı yüklenmiş iki işlevi tanımlamak yerine şablonları kullanmaktır. Programcı türü dikkate almak zorunda kalmadan, fonksiyonun aşağıdaki gibi çağrılmasını tercih ederim

isFunction(aVariable) // and not isFunction<int> (aVariable) nor isFunction<anEnum> (aVariable)

Temel olarak, bu fonksiyonun int ve aNum tipleri için şablonlaştırılmasını istiyorum. Bunu aradım, ancak cevabı bulamadım. Ne eksik olabilirim? Teşekkür ederim,


Tam olarak tek bir enum veya int türüyse, neden her iki işlevi de yazmıyorsunuz? Bu durumda neden bir şablona ihtiyacınız var?
Klaus

Diğer türler ne olacak? falseDiğer türler için geri dönmek mi yoksa diğer türler için işlevi somutlaştırmak istemiyorsanız.
frogatto

@frogatto Hayır, bool dönüş değerinin türünde bir şey yok.
bg

@Klaus Alternatifleri öğrenmek istedim. Mevcut cevaplara dayanarak, her iki işlevi de tanımlamaya karar verdim.
bg

Yanıtlar:


25

C ++ 20 olmayan yanıta ek olarak, herhangi bir şansla, C ++ 20 ve conceptsözelliğini kullanabiliyorsanız, size aşağıdaki uygulamayı öneririm:

#include <iostream>
#include <concepts>

enum class MyEnum {
    A,
    B,
    C
};

template <typename T>
concept IntegralOrEnum = std::same_as<MyEnum, T> || std::integral<T>;

template <IntegralOrEnum T>
bool isFunction(T const& aVariable) {
    return true;
}

int main() {
    isFunction(MyEnum::A);
    isFunction(3);
    isFunction("my_string"); // error
    return 0;
}

gösteri

GÜNCELLEME

@RichardSmith'in yorumuna göre , işte daha ölçeklenebilir ve tekrar kullanılabilir bir yaklaşım:

template <typename T, typename ...U>
concept one_of = (std::is_same_v<T, U> || ...);

template <one_of<int, MyEnum> T>
bool isFunction(T const& aVariable) {
    return true;
}

Türün iki belirli türden biri olmasını gerektiren belirli bir durumda, bunun gibi bir şey daha iyi olabilir:template<typename T, typename ...U> concept one_of = (std::is_same_v<T, U> || ...); template<one_of<int, MyEnum> T> bool isFunction(T const& aVariable) {
Richard Smith

1
@RichardSmith Cevabımı da bununla güncelledim. Bunu daha çok yeniden kullanılabilir ve ölçeklenebilir buluyorum. Thanks
NutCracker

21

Bunu başarmanın birkaç yolu vardır. Hepsi type_traitsüstbilgiyi kullanmayı içerir . Söz konusu işlevin gövdesinde söz konusu türler hakkında statik iddiada bulunabilirsiniz.

Veya, bu fonksiyonu diğer aşırı yüklenmeler arasında dikkate almanız gerekirse, bir SFINAE tekniği kullanılabilir.

template<typename T>
auto isFunction(const T &aVariable) 
  -> std::enable_if_t<std::is_same<T, int>::value || std::is_same<T,anEnum>::value, bool> {
}

Bu, türler eşleşmezse çağrılmadan önce işlevi bir aşırı yük kümesinden kaldıracaktır. Ancak, bu davranışa ihtiyacınız yoksa, statik bir iddia daha programcı dostu bir hata iletisine izin verir.


3

Bu çözüm ne olacak? T tipi gereksinimlerinizi karşılarsa, işleve sahip bir kod derlenecektir. Aksi takdirde, statik iddia başarısız oldu.

#include <type_traits>
enum anEnum {
    //
};

template <typename T, bool defined = std::is_same<T, int>::value ||
                                     std::is_same<T, anEnum>::value>
bool isFunction(const T& aVariable)
{
    static_assert(defined, "Invalid specialization");

    bool result = false;
    // Put your code here
    return result;
}

1
Başka imzalar varsa (örn isFunction(std::string_view). Varsayımsal ) , aşırı yük çözünürlüğü ile iyi çalışmaz . İmza yine de geçerli bir eşleşme olacaktır, ancak örnekleme hataya neden olur.
LF

Yararsız imzaları silindi olarak bildirebilirsiniz: bool isFunction (std :: string_view) = delete;
ixjxk

Ek aşırı yüklemelerden bahsediyorum. Bu durumda, bu geçersiz imza kesin bir eşleşme olabilir (örneğin, dizgi değişmezleri için), böylece aşırı yüklenmeyi engeller.
LF

0

Https://stackoverflow.com/a/60271100/12894563 yanıtını geliştirdim . 'Eğer constexpr' bu durumda yardımcı olabilir:

template <typename T>
struct always_false : std::false_type {};

template <typename T>
bool isFunction(const T& aVariable)
{
    if constexpr(std::is_same_v<T, int> || std::is_same_v<T, anEnum>)
    {
        std::cout << "int\n";
        // put your code here
        return true;
    }
    else
    {
        static_assert(always_false<T>::value, "You should declare non-template function or write if constexpr branch for your type");
        return false;
    }
}

bool isFunction(std::string_view)
{
    std::cout << "std::string_view\n";
    return true;
}

int main()
{
    isFunction(std::string_view("1L"));
    isFunction(1);
    //isFunction(1L); // will produce an error message from static_assert
}

Aşırı yüklenmiş fonksiyon veya 'if constexpr' dalı olmadığından isFunction (1L) başarısız olur.

GÜNCELLEME: Sabit cevapsız

template <typename T>
struct always_false : std::false_type {};

https://godbolt.org/z/eh4pVn


static_assert(false, ...)kullanılmadan bile kötü biçimlendirilmiş NDR'dir. Eğer şanslıysanız, derleyiciniz Clang'ın
StoryTeller - Unslander Monica

Yorumunuz için çok teşekkürler, bir hata yaptım. Düzeltildi, godbolt.org/z/eh4pVn
ixjxk
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.