Summit
Summit

Reputation: 2268

Why do i get compile error while using template function

I have a base class.

#include <string.h>
class Channel
{
private:
    std::string stdstrName;

public:
    Channel() : stdstrName("CHANNEL"){   }
    Channel(std::string name) : stdstrName(name){ }
    void PrintName() { std::cout << stdstrName << std::endl; }  
};

which is inherited by Position class.

class PositionChannel : public Channel
{
public:
    std::vector<int> keyframes;
    PositionChannel() : Channel("POSITION") , keyframes( { 1 , 2, 3 }) {    }
};

There is a director class which has the channel clas as its data members.

#include "Channel.h"
#include <memory>

class Director
{
private:
    std::vector<std::shared_ptr<Channel>> channels;

public:
    void AddChannel(std::shared_ptr<Channel> chn) { channels.push_back(chn); }
    void GetChannel(Channel **chn) { *chn = channels[0].get(); }   
};

now when in the main function.

 // Free function
 template<typename T>
    void GetChannel(Director *dir)
    {
        T *chn;
        dir->GetChannel(&chn);
    }

    Director dir;
    PositionChannel channel;
    std::shared_ptr<Channel> channelPointer = std::make_shared<Channel>(channel);
    dir.AddChannel(channelPointer);
    GetChannel< PositionChannel>(&dir); // here i get error  

this is the error message error C2664: ' cannot convert argument 1 from 'T **' to 'Channel **

if i change the templated function to a non templted function than i do not get any error.

Upvotes: 0

Views: 84

Answers (3)

Vasilij
Vasilij

Reputation: 1941

Yes, Daniel Langr already gave the correct answer. I added a check in the template if the class is derived.

#include <type_traits>
class Channel
{ 
    public:
    virtual ~Channel() = default;
};

class PositionChannel : public Channel
{ 
};

struct Director{
    void GetChannel(Channel **c) {}
};
 
template <typename T,
typename = typename std::enable_if<std::is_base_of<Channel, T>::value, T>::type>
void GetChannel(Director *dir)
{
    Channel *chn;
    dir->GetChannel(&chn);
    T* ptr = static_cast<T*>(chn);
}

int main(void) {
    Director dir;
    GetChannel<PositionChannel>(&dir);
    return 0;
}

Upvotes: 0

Daniel Langr
Daniel Langr

Reputation: 23497

In you GetChannel call, &chn argument is of type PositionChannel**, but the type of Director::GetChannel parameter is Channel**. These two types are not convertible; see, for example this question: Conversion of pointer-to-pointer between derived and base classes?.

I am not sure what are your intentions since the code does not make much sense as is, but you can redefine GetChannel as follows:

template<typename T>
void GetChannel(Director *dir)
{
  Channel* ptr;
  dir->GetChannel(&ptr);
  T *chn = ptr;
}

Upvotes: 4

ShadowMitia
ShadowMitia

Reputation: 2533

T can be any type, you can't convert it to a Channel for any type.

There are probably ways to make it work with templates, but I feel like your problem could be more easily solved by using polymorphism with something like this :

void GetChannel(Channel* chn, Director *dir)
{
    dir->GetChannel(&chn);
}

And then chn can be any type dervived from Channel.

Upvotes: 1

Related Questions