Kelebihan fungsi menggunakan templat

34

Saya mencoba untuk mendefinisikan suatu fungsi menggunakan template dan saya ingin nama ketik menjadi int atau anEnum (enum spesifik yang telah saya tetapkan). Saya sudah mencoba yang berikut tetapi saya gagal:

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

Apa yang saya coba lakukan adalah menggunakan template, alih-alih mendefinisikan dua fungsi yang kelebihan beban. Saya lebih suka fungsi dipanggil sebagai berikut, tanpa programmer harus mempertimbangkan jenisnya

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

Pada dasarnya, saya ingin fungsi ini digunakan untuk tipe int dan aNum. Saya telah mencari ini, tetapi tidak dapat menemukan jawabannya. Apa yang mungkin saya lewatkan? Terima kasih,

bg
sumber
Jika itu persis enum tunggal atau tipe int, mengapa tidak menulis kedua fungsi saja? Mengapa Anda membutuhkan templat dalam kasus itu?
Klaus
Bagaimana dengan tipe lain? Apakah Anda ingin kembali falseuntuk jenis lain atau ingin tidak instantiate fungsi untuk jenis lain.
frogatto
@frogatto Tidak, nilai pengembalian bool tidak memiliki apa pun dengan tipe.
bg
@ Klaus Saya sudah minta belajar alternatif. Berdasarkan jawaban saat ini, saya telah memutuskan untuk mendefinisikan kedua fungsi.
bg

Jawaban:

25

Selain jawaban non-C ++ 20, jika Anda, secara kebetulan, dapat menggunakan C ++ 20 dan conceptsfiturnya, saya akan menyarankan Anda penerapan berikut:

#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;
}

Demo

MEMPERBARUI

Menurut komentar @RichardSmith , berikut ini adalah pendekatan yang lebih terukur dan dapat digunakan kembali:

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;
}
Alat pemecah buah keras
sumber
Untuk kasus spesifik yang mengharuskan tipe menjadi salah satu dari dua tipe spesifik, sesuatu seperti ini mungkin bekerja lebih baik: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 Saya telah memperbarui jawaban saya juga. Saya menemukan ini lebih dapat digunakan kembali dan terukur. Terima kasih
NutCracker
21

Ada beberapa cara untuk mencapai ini. Semua melibatkan penggunaan type_traitsheader. Misalnya, Anda dapat menegaskan secara statis tentang jenis yang dimaksud di badan fungsi.

Atau, jika Anda perlu mempertimbangkan fungsi ini di antara kelebihan beban lainnya, teknik SFINAE dapat digunakan.

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> {
}

Ini akan menghapus fungsi dari set overload sebelum dipanggil jika tipe tidak cocok. Tetapi jika Anda tidak memerlukan perilaku ini, pernyataan statis memang memungkinkan untuk pesan kesalahan yang lebih ramah programmer.

StoryTeller - Unslander Monica
sumber
3

Bagaimana dengan solusi ini? Kode dengan fungsi akan dikompilasi jika tipe T memenuhi syarat Anda. Jika tidak, pernyataan statis gagal.

#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;
}
ixjxk
sumber
1
Ini tidak bekerja dengan baik dengan resolusi kelebihan jika ada tanda tangan lain hadir (misalnya, hipotetis isFunction(std::string_view)). Tanda tangan masih akan menjadi kecocokan yang valid, tetapi instantiasi menyebabkan kesalahan.
LF
Anda dapat mendeklarasikan tanda tangan yang tidak berguna sebagai dihapus: bool isFunction (std :: string_view) = delete;
ixjxk
Saya sedang berbicara tentang kelebihan tambahan. Dalam hal itu, tanda tangan yang tidak valid ini mungkin berakhir dengan kecocokan persis (misalnya, untuk string literal), sehingga memblokir kelebihan.
LF
0

Saya telah meningkatkan https://stackoverflow.com/a/60271100/12894563 jawaban. 'Jika constexpr' dapat membantu dalam situasi ini:

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
}

isFunction (1L) akan gagal karena tidak ada fungsi kelebihan beban atau cabang 'jika constexpr'.

UPDATE: Tetap terjawab

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

https://godbolt.org/z/eh4pVn

ixjxk
sumber
static_assert(false, ...)adalah NDR yang buruk, bahkan tanpa digunakan. Jika Anda beruntung, kompiler Anda akan memberitahu Anda segera, seperti dentang tidak, godbolt.org/z/m_Gk9n
StoryTeller - Unslander Monica
Terima kasih banyak atas komentar Anda, saya membuat kesalahan. Diperbaiki, godbolt.org/z/eh4pVn
ixjxk