简体   繁体   中英

Templates C++ error : could not deduce template argument

I am trying ot add a function template that will print if it contains precision values or valves and the value. The rest of the program works except this function. I am not sure what I am doing wrong but the error I recieve is:

error C2784: 'void printInstrumentDetail(const I *const )' : could not deduce template argument for 'const I *const ' from 'std::vector<_Ty>'

#include <iostream>
#include <vector>
#include <iomanip>
#include <string>
#include "Instruments.h"
#include "Brass.h"
#include "Strings.h"

using namespace std;

//template<typename I>                    <---Problem
//void printInstrumentDetail(const I * const a)
//{
//      for (size_t i = 0; i < 6; i ++)
//  {
//      cout << "The details for " << a[i]->getName()
//          << ": " << a[i]->print();
//  }
//}
int main()
{
    double total = 0;

    Strings violin("Violin", 553.90, 3);
    Strings cello("Cello", 876.45, 3);
    Strings viola("Viola", 200.50, 23);
    Brass tuba("Tuba", 1400.10, 1.23);
    Brass trumpet("Trumpet", 500.00, 4.32);
    Brass sax("Sax", 674.78, .99);

    vector <Instruments *> band(6);

    band[0] = &violin;
    band[1] = &tuba;
    band[2] = &cello;
    band[3] = &trumpet;
    band[4] = &viola;
    band[5] = &sax;

    cout << fixed << setprecision(2);

    cout << "The instruments in the band are:\n";
    //Get name and cost of each
    for (size_t i = 0; i < 6; i ++)
    {
        cout << band[i]->getName() << "     $" 
            << band[i]->getCost() << endl;
    }

    cout << "\nThen band is warming up..." << endl;
    //Get descrition of how sound is made of each
    for (size_t i = 0; i < 6; i ++)
    {
        cout << "This " << band[i]->getName()
            << " makes sounds by " ;
        band[i]->playSound();
    }
    cout << "\nTotal cost of the band is: $" ;
    //Get total cost of all instruments
    for (size_t i = 0; i < 6; i ++)
    {

        total = band[i]->getCost() + total;
    }
    cout << total << endl;

    //printInstrumentDetail(band);                     <--Problem

    return 0;
}

Here's the base class:

#ifndef INSTRUMENTS_H
#define INSTRUMENTS_H

#include <string>

using namespace std;

class Instruments
{
public:
    Instruments(string, double);

    void setName(string);
    virtual string getName();

    void setCost(double);
    virtual double getCost();

    virtual void print();

    virtual void playSound();

private:
    string name;
    double cost;
};
#endif

#include <iostream>
#include "Instruments.h"

using namespace std;

Instruments::Instruments(string n, double c)
{
    name = n;
    cost = c;
}
void Instruments::setName(string n)
{
    name = n;
}
string Instruments::getName()
{
    return name;
}
void Instruments::setCost(double c)
{
    cost = c;
}
double Instruments::getCost()
{
    return cost;
}
void Instruments::print() 
{

}
void Instruments::playSound()
{
    //empty
}

Derived class Bass:

#ifndef BRASS_H
#define BRASS_H

#include <string>
#include "Instruments.h"

using namespace std;

class Brass : public Instruments
{
public:
    Brass(string, double, double);

    void setPrecisionValue(double);
    double getPrecisionValue();
    void print() ;
     void playSound();

private:
    double precision;
    string sound;
};
#endif

#include <iostream>
#include "Brass.h"

using namespace std;

Brass::Brass(string n, double c, double p)
:Instruments(n, c)
{
    precision = p;
}
void Brass::setPrecisionValue(double p)
{
    precision = p;
}
double Brass::getPrecisionValue()
{
    return precision;
}
void Brass::print() 
{
    cout << getPrecisionValue() << endl;
}
void Brass::playSound()
{
    cout << "blowing in a mouthpiece." << endl;
    Instruments::playSound();
}

Derived class Strings:

#ifndef STRINGS_H
#define STRINGS_H

#include <string>
#include "Instruments.h"

using namespace std;

class Strings : public Instruments
{
public:
    Strings(string, double, int);

    void setValves(int);
    int getValves();
    void print();
    void playSound();

private:
    int valves;
};
#endif

#include <iostream>
#include "Strings.h"

using namespace std;

Strings::Strings(string n, double c, int v)
    :Instruments(n, c)
{
    valves = v; 
}
void Strings::setValves(int v)
{
    valves = v;
}
int Strings::getValves()
{
    return valves;
}
void Strings::print() 
{
    cout<< getValves() << endl;
}
void Strings::playSound()
{
    cout << "striking with a bow." << endl;
    Instruments::playSound();
}

Well, the problem is that your template requires a pointer:

template<typename I>   
void printInstrumentDetail(const I * const a);

but you're giving it a vector, not a pointer:

vector <Instruments *> band(6);
...
printInstrumentDetail(band);

You can hack your way around this by passing a pointer to the printInstrumentDetail function, like so:

printInstrumentDetail(&band[0]);

But really, you'd be much better off modifying printInstrumentDetail to take a container or a pair of iterators:

template <typename ContainerT>   
void printInstrumentDetail(const ContainerT& a)

or

template <typename IteratorT>
void printInstrumentDetail(IteratorT first, IteratorT last)

with the appropriate modifications to the definition of the function.

Pass the pointer to vector

printInstrumentDetail(&band);   

and inside printInstrumentDetail

(*a)[i]->getName();

Well, first off I don't believe you can pass a vector as a const * I const at

printInstrumentDetail(band);

Vector cannot be just cast to a pointer. One working solution would be something like:


template <typename T>
void printInstrumentDetail( const std::vector<T*>& band )
{
    for ( size_t i = 0; i < band.size(); ++i )
        cout << "The details for " << band[i]->getName()
             << ": " << band[i]->print();
}

And there are many others, including iterators, functors, STL algorithms, etc.

You are trying to pass an object to an interface that wants a pointer.

void printInstrumentDetail(const I * const a)

Convert this to a reference.

void printInstrumentDetail(I const I& a)

But to conform to the pattern that is common in C++. You should pass the beginning and end of the sequence as parameters. ie change your function to take itertors rather than a pointer.

Instead of passing the pointer:

printInstrumentDetail(const I * const a)  

you can pass the reference:

printInstrumentDetail(const I& a)

Everything else stays unchanged.

First of all, there seems to be no reason for PrintInstrumentDetail to be a template at all -- it works with pointers to the base class, and unless you're likely to have other types with getName() and print() members to which it might be applied, it can/could/should just work with pointers to the base class.

Second, I'd think hard about changing how you do the job. Instead of a member function in each Instrument, and PrintInstrumentDetail to loop over all the instruments, I'd think hard about defining operator<< for Instrument, and using a standard algorithm to print out the details.

Looking at it, I think a few other things should change as well. First of all, unless you're dealing with really unusual instruments, the number of valves on a brass instrument is fixed forever -- so it should NOT have a SetValve() member. Rather, the number of valves should be set during construction, but not be open to change afterwards.

String instruments don't have valves at all (at least most normal ones don't), so they shouldn't have SetValves() , GetValves() , or anything else related to valves.

Likewise, unless you're doing something pretty unusual, the cost of an instrument can never change -- you paid what you paid, so the cost should be set during construction, and not open to later alteration.

Edit: one other thing: instead of hard-coding 6 everywhere, use band.size() to loop over all the instruments in the band.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM