2

I don't know what to do. I always get an error by using a simple class and a simple template function. I read all the other solutions but they didn't helped me.

Next to some other classes I have the simple class Data:

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

and the function dat:

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

As you can see, I want to check the id and return int, double or char. Now I've tried to print the value in the main function like this:

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

But I always get this error message:

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

Where is the problem??

Thank you

  • 2
    Also, a template function instantiates a concrete function (I'm abusing terminology here, it's just to make a point) with a single return type. So you can't return things which are not of the declared return type, not without implicit conversions or casting anyway. The body of your template function implies you don't fully grasp the concept yet. – StoryTeller - Unslander Monica Nov 27 '13 at 12:45
  • As another side note, it seems you are trying to do, in a limited fashion, exactly what the classes James Kanze mentioned do. Have a look at those instead. – StoryTeller - Unslander Monica Nov 27 '13 at 12:50
  • What are you *really* trying to do? Having to specify `dat`, or `dat` or `dat` *and* use a flag to decide the type is confused and could potentially cause quite a few bugs. – doctorlove Nov 27 '13 at 12:51
  • I'm not trying anything, my prof wants me to try it this way. I have to write a class for a linked queue with nodes of different types in it. – Christian Manthey Nov 27 '13 at 13:19

5 Answers5

4

To put it precisely, you want the return type of the function to depend on it's the id field in the object; in other words, dynamically. Templates are resolved at compile time, so they cannot help here. You'll have to return something like boost::variant or boost::any, which supports such dynamic typing.

James Kanze
  • 150,581
  • 18
  • 184
  • 329
  • Thanks a lot, I tried boost::variant. It seems to be a nice solution, but I don't think that this is the solution my prof wants to see. – Christian Manthey Nov 27 '13 at 14:20
  • @ChristianManthey If I've understood the problem correctly, either using `boost::variant`, or reimplementing something similar and using it, is the only real solution. (And reimplementing something like `boost::variant` correctly is a non-trivial undertaking, and definitely beyond the scope of someone learning the language.) – James Kanze Nov 27 '13 at 17:30
1

Use this:

cout<<test.dat<int>();
Manish Mulimani
  • 17,535
  • 2
  • 41
  • 60
1

dat() has no parameters involving T, so the compiler cannot deduce T from the call and it must be provided explicitly, e.g.:

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

Also, bear in mind you must implement dat() in the header file.

Community
  • 1
  • 1
Angew is no longer proud of SO
  • 167,307
  • 17
  • 350
  • 455
1

I don't know what to do. I always get an error by using a simple class and a simple template function. I read all the other solutions but they didn't helped me.

It seems to me that you want to create a discriminated union.

Your implementation won't work, because the return type of a template function is determined at compilation time (i.e. before you set a value in id and try to call the function.

Solution:

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

Client code:

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

All that said, you should consider using a boost::variant or boost::any instance, depending on your needs.

utnapistim
  • 26,809
  • 3
  • 46
  • 82
  • You could create a type traits class that returns the type (Data::discriminator) of the argument and you'd then have a single (generic) `get` implementation. That would be advantageous if you had to write more functions (e.g. also a `get_or_default(const T& deflt)`. – utnapistim Nov 28 '13 at 09:14
0

VS2012 says "error C2783: 'T Data::dat(void)' : could not deduce template argument for 'T'"

You just need to tell the function dat what T is:

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

The template type can be deduced if you pass a templated parameter, but it cannmot guess the return type.

doctorlove
  • 18,872
  • 2
  • 46
  • 62
  • He's returning a different type depending on one of the fields in the object. In other words: the return type should depend on runtime data. I don't think templates can help here. – James Kanze Nov 27 '13 at 12:47
  • I agree - this (and the similar answers) will deal with the current compiler error, but the premise is wrong. We should ask what the OP is really trying to do. – doctorlove Nov 27 '13 at 12:48