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

4
  • 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. Commented Nov 27, 2013 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. Commented Nov 27, 2013 at 12:50
  • What are you really trying to do? Having to specify dat<int>, or dat<char> or dat<double> and use a flag to decide the type is confused and could potentially cause quite a few bugs. Commented Nov 27, 2013 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. Commented Nov 27, 2013 at 13:19

5 Answers 5

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.

Sign up to request clarification or add additional context in comments.

2 Comments

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.
@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.)
1

Use this:

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

1 Comment

And what happens if id is 2, and he wants to return a double?
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.

Comments

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.

1 Comment

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).
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.

2 Comments

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.
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.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.