Можно ли вызвать метод класса и глобальный метод на основе параметров шаблона класса? - PullRequest
4 голосов
/ 25 октября 2019

Это моя проблема:

#include <string>



struct Print
{
    template <typename T>
    void Printer( const T& data )
    {
        PrinterInstance( data );
    }


    void PrinterInstance( const int& data )
    {
        printf( "INTEGER\n" );
    }
};



void PrinterInstance( const std::string& data )
{
    printf( "STRING\n" );
}



int main()
{
    Print print;
    print.Printer( "3" );
    return 0;
}

Внутри класса Print у меня есть шаблон Printer, который в основном вызывает PrinterInstance на основе параметров шаблона. Кроме того, я должен иметь возможность расширить эту функциональность, добавив больше PrinterInstance вне класса.

Но это не компилируется. Если я реализую PrinterInstance только внутри класса, это нормально. Если я реализую PrinterInstance только вне класса, это тоже нормально. Но как только у меня есть один PrinterInstance внутри класса и один вне класса, шаблон будет пытаться использовать только класс 1.

Можно ли заставить эту работу работать?

РЕДАКТИРОВАТЬ: он долженработа на С ++ 11.

Ответы [ 3 ]

2 голосов
/ 26 октября 2019

Если вы можете добавить шаблон PrinterInstance() внутри Print

template <typename T>
void PrinterInstance (T const & data)
 { ::PrinterInstance(data); }

, который вызывает глобальный PrinterInstance(), у вас есть то, что компилятор использует метод PrinterInstance(), когда тип является точнымсоответствие, глобальная версия (проходящая через метод шаблона) в противном случае.

Но, как и в ответе LeDYoM, это требует, чтобы глобальные версии PrinterInstance() были определены (или, по крайней мере, объявлены) передPrinter body.

Ниже приведен полный пример компиляции

#include <string>
#include <iostream>

void PrinterInstance ( const std::string& data )
 { std::cout << "STRING, " << data << std::endl; }

struct Print
 {
   template <typename T>
   void Printer (T const & data)
    { PrinterInstance( data ); }

   template <typename T>
   void PrinterInstance (T const & data)
    { ::PrinterInstance(data); }

   void PrinterInstance (int const & data)
    { std::cout << "INTEGER, " << data << std::endl; }
 };

int main ()
 {
   Print p;
   p.Printer("3");
   p.Printer(5);
 }
1 голос
/ 26 октября 2019

Если вы можете использовать C ++ 17:

#include <string>
#include <type_traits>

void PrinterInstance( const std::string& data );

struct Print
{
    template <typename T>
    void Printer( const T& data )
    {
        if constexpr (std::is_same_v<T,int>)
        {
            PrinterInstance( data );
        }
        else
        {
            ::PrinterInstance(data);
        }
    }

    void PrinterInstance( const int& data )
    {
        printf( "INTEGER\n" );
    }
};

void PrinterInstance( const std::string& data )
{
    printf( "STRING\n" );
}

int main()
{
    Print print;
    print.Printer( "3" );
    return 0;
}

Примечание: бесплатный PrintInstance должен быть объявлен первым. (Или все перегрузки, которые вы хотите). Вы можете добавить в if constexpr столько типов, сколько вам нужно (перегрузки внутри структуры). Вы, вероятно, можете перевести его на C ++ 14 и немного SFINAE.

Код: https://godbolt.org/z/S1ZJ93

0 голосов
/ 26 октября 2019

Проблема заключается в том, что член скрывает функции в области имен.

Одним из решений является отправка правильной функции, например:

void PrinterInstance( const std::string& data )
{
    printf( "STRING\n" );
}

// Declarations of PrinterInstance for built-in should also be visible before `Printer`

struct Print
{
    template <typename T>
    void Printer( const T& data )
    {
        if constexpr (std::is_invocable<decltype(&Print::PrinterInstance), Print, T>::value) {
            PrinterInstance( data );
        } else {
            using ::PrinterInstance; // make function at global scope visible,
                                     // hide member function and so allows ADL
            PrinterInstance( data );
        }
    }


    void PrinterInstance( const int& data )
    {
        printf( "INTEGER\n" );
    }
};

namespace N
{
    struct S{};

    void PrinterInstance( const N::S& )
    {
        printf( "S\n" );
    }
}

Демо

В C ++ 11 это может быть:

struct Print
{
    template <typename T>
    void Printer( const T& data );

    void PrinterInstance( char data )
    {
        printf( "CHAR\n" );
    }

    void PrinterInstance( const int& data )
    {
        printf( "INTEGER\n" );
    }
};

template <typename T>
auto printerImpl(Print& p, const T& arg) -> decltype(p.PrinterInstance(arg))
{
    return p.PrinterInstance(arg);
}

template <typename T>
auto printerImpl(Print&, const T& arg) -> decltype(PrinterInstance(arg))
{
    return PrinterInstance(arg);
}

template <typename T>
void Print::Printer( const T& data )
{
    printerImpl(*this, data);
}

Демо

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...