2013-11-27 7 views
2

Я не знаю, что делать. Я всегда получаю ошибку, используя простой класс и простую функцию шаблона. Я прочитал все другие решения, но они мне не помогли.Функция шаблона в классе

Рядом с некоторыми другими классами у меня есть простой класс данных:

class Data{ 
public: 
    template <class T> 
    T dat(); 
    int id; 
    union{ 
     char c; 
    int i; 
    double d; 
    }; 
}; 

и функцию DAT:

template <class T> 
T Data::dat(){ 
    if(id == 1) return i; 
    if(id == 2) return d; 
    if(id == 3) return c; 
} 

Как вы можете видеть, я хочу проверить Ид и возвращения Int, double или char. Теперь я пытался напечатать значение в главной функции, как это:

Data test; 
test.id=1; 
test.i = 12; 
cout<<test.dat(); 

Но я всегда получаю сообщение об ошибке:

Error: Could not find a match for Data::dat<Data::T>() needed in main(int, char**). 

Где проблема ??

Спасибо

+2

Кроме того, функция шаблона создает конкретную функцию (я использую терминологию здесь, это просто точка) с одним возвращаемым типом. Таким образом, вы не можете возвращать вещи, которые не относятся к объявленному типу возврата, но не без неявных преобразований или кастингов. Тело вашей функции шаблона подразумевает, что вы еще не полностью понимаете концепцию. – StoryTeller

+0

Как другая сторона примечания, кажется, вы пытаетесь сделать, в ограниченном порядке, именно то, что упомянули классы Джеймса Канзе. Посмотрите на них. – StoryTeller

+0

Что вы на самом деле пытаетесь сделать? Чтобы указать 'dat ', или 'dat ' или 'dat ' * и * использовать флаг, чтобы решить, что тип запутан и может вызвать множество ошибок. – doctorlove

ответ

1

Используйте это:

cout<<test.dat<int>(); 
+0

И что произойдет, если 'id' равно 2, и он хочет вернуть' double'? –

1

dat() не имеет параметров, связанных с T, поэтому компилятор не может вывести T из вызова, и она должна быть предоставлена ​​в явном виде, например:

cout << test.dat<int>(); 

Кроме того, несут ум вы должны implement dat() in the header file.

4

Чтобы выразить это, вы хотите, чтобы возвращаемый тип функции был равен , зависит от его поля id; другими словами, динамически. Шаблоны разрешаются во время компиляции, поэтому они не могут помочь здесь . Вам нужно будет вернуть что-то вроде boost::variant или boost::any, которое поддерживает такую ​​динамическую печать .

+0

Большое спасибо, я попробовал boost :: variant. Кажется, это приятное решение, но я не думаю, что это решение, которое хочет видеть мой проф. –

+0

@ChristianManthey Если я правильно понял проблему, либо использование 'boost :: variant', либо переопределение чего-то подобного и использование его, является единственным реальным решением. (И переопределение чего-то типа «boost :: variant» правильно - это нетривиальное обязательство и, безусловно, выходит за рамки того, кто изучает язык.) –

0

VS2012 говорит "C2783 ошибка: 'T Data :: Дат (аннулируются)': не может вывести аргумент шаблона для 'T'"

Вам просто нужно сказать функцию dat, что T является:

cout<<test.dat<int>(); 

Тип шаблона может быть выведен, если вы передадите шаблонный параметр, но он не может угадать тип возврата.

+0

Он возвращает другой тип в зависимости от одного из полей объекта. Другими словами: тип возврата должен зависеть от данных времени выполнения. Я не думаю, что шаблоны могут помочь здесь. –

+0

Я согласен - это (и аналогичные ответы) будет касаться текущей ошибки компилятора, но предпосылка неверна. Мы должны спросить, что действительно пытается сделать OP. – doctorlove

1

Я не знаю, что делать. Я всегда получаю ошибку, используя простой класс и простую функцию шаблона. Я прочитал все другие решения, но они мне не помогли.

Мне кажется, что вы хотите создать дискриминационный союз.

Ваша реализация не будет работать, потому что тип возврата функции шаблона определяется во время компиляции (т. Е. До того, как вы установите значение в id и попытаетесь вызвать функцию.

Решение:

class Data 
{ 
    enum value_type { 
     int_val, char_val, double_val 
    } discriminator; // private (the user doesn't see this) 
        // this replaces your id 

    union{ 
     char c; 
     int i; 
     double d; 
    } value; 

public: 
    class wrong_type_error: public std::logic_error 
    { 
    public: 
     wrong_type_error(const std::string& msg): std::logic_error(msg) {} 
    }; 

    explicit Data(const char c) 
    : discriminator(Data::char_value) 
    , value.c(c) 
    { 
    } 

    explicit Data(const int i) 
    : discriminator(Data::int_value) 
    , value.i(i) 
    { 
    } 

    explicit Data(const double d) 
    : discriminator(Data::double_value) 
    , value.d(d) 
    { 
    } 

    // don't put this here: int id; 

    // this part can be optimized to simpler (more idiomatic) code 
    template<typename T> T get() const; // undefined 
    template<> int get() const { 
     if(discriminator != Data::int_val) 
      throw wrong_type_error("Cannot return a int from Data instance"); 
     return value.i; 
    } 
    template<> char get() const { 
     if(discriminator != Data::char_val) 
      throw wrong_type_error("Cannot return a char from Data instance"); 
     return value.c; 
    } 
    template<> double get() const { 
     if(discriminator != Data::double_val) 
      throw wrong_type_error("Cannot return a double from Data instance"); 
     return value.d; 
    } 
}; 

код клиент:

Data test(10.5); 
cout<<test.get<double>(); 

Все, что сказал, вы должны рассмотреть возможность использования повышающего :: варианта или повышение :: любой экземпляр, в зависимости от ваших потребностей.

+0

+1. Мне любопытно узнать, насколько более идиоматичным может быть код. – StoryTeller

+0

Вы можете создать класс признаков типов, который возвращает тип (Data :: дискриминатор) аргумента, и тогда у вас будет одна (общая) реализация 'get'. Это было бы полезно, если бы вам пришлось писать больше функций (например, также 'get_or_default (const T & deflt)'. – utnapistim

Смежные вопросы