gpt4 book ai didi

c++ - 如何在使用派生实例调用模板基类的好友函数时避免使用 “std::static_pointer_cast”

转载 作者:行者123 更新时间:2023-12-01 14:57:02 30 4
gpt4 key购买 nike

我有一个带有 friend 功能的模板基类,它可以对另一个类进行操作(connect)。如果我从此类模板库派生一个类,则在调用传递派生类实例的好友函数时需要使用std::static_pointer_cast<base<whatever_type>>,我想找到一种方法让好友函数接受派生类的实例而不必执行static_pointer_cast。我想我需要找到一种方法来声明 friend 功能,以便模板参数推导能解决?
代码如下:

#include <memory>
#include <queue>
#include <vector>
#include <unordered_map>

template<class T>
class base;

template<class T>
class extractor;

template<class T>
auto connect(std::shared_ptr<base<T>> node,
std::shared_ptr<extractor<T>> ext);

// A queue adaptator that allows only to pop elements
template<class ValueType>
class extractor
{
public:
friend auto connect<ValueType>(std::shared_ptr<base<ValueType>>,
std::shared_ptr<extractor<ValueType>>);

void pop()
{
queue->pop();
}

private:
std::shared_ptr<std::queue<ValueType>> queue;
};


// A collection of replicated queues that allows only to push elements
template<class T = void*>
class base
{
public:

friend auto connect<T>(std::shared_ptr<base<T>>,
std::shared_ptr<extractor<T>>);

void push(const T& e)
{
for (auto & o : output)
{
o.second->push(e);
}
}

private:
std::unordered_map<std::shared_ptr<extractor<T>>,
std::shared_ptr<std::queue<T>>> output;
};

template<class T>
auto connect(std::shared_ptr<base<T>> node,
std::shared_ptr<extractor<T>> ext)
{
if (ext == nullptr)
{
ext.reset(new extractor<T>);
}

auto q = std::make_shared<std::queue<T>>();
node->output.emplace(ext, q);
ext->queue = q;
}


// A user type that puts number 42
class foo : public base<int>
{
public:

void do_something()
{
push(42);
}

};

// A user type that pops from an input
class bar : public base<>
{
public:
std::shared_ptr<extractor<int>> input;

void do_something_else()
{
input->pop();
}
};

int main(int argc, char** argv)
{
auto pusher = std::make_shared<foo>();
auto poper = std::make_shared<bar>();

// Here is the problem: I do not want client code to have to use "static_pointer_cast"
connect(std::static_pointer_cast<base<int>>(pusher), poper->input);

// Would like to be able to use:
connect(pusher, poper->input);

return 0;
}
如果我不做 static_pointer_cast会发出Clang错误:
stack_overflow.cpp:107:5: error: no matching function for call to 'connect'
connect(pusher, poper->input);
^~~~~~~
stack_overflow.cpp:58:6: note: candidate template ignored: could not match 'base<type-parameter-0-0>' against 'foo'
auto connect(std::shared_ptr<base<T>> node,

最佳答案

问题在于,编译器将尝试从给定参数推导类型T,并且无法将foo解析为参数base<int>。尝试匹配模板参数时,不考虑强制转换为基本类型,这与匹配重载集中的函数相反。
在这种特殊情况下,由于类型T已经可以从第二个函数参数中确定,因此您可以告诉编译器不要尝试匹配第一个参数,例如,通过以这种方式更改connect()的声明:

template <typename T>
struct identity
{
using type = T;
};

template<class T>
auto connect(std::shared_ptr<base<typename identity<T>::type>> node,
std::shared_ptr<extractor<T>> ext);
将其插入完整的示例将呈现以下内容:
#include <memory>
#include <queue>
#include <vector>
#include <unordered_map>

template<class T>
class base;

template<class T>
class extractor;

template <typename T>
struct identity
{
using type = T;
};

template<class T>
auto connect(std::shared_ptr<base<typename identity<T>::type>> node,
std::shared_ptr<extractor<T>> ext);

// A queue adaptor that allows only to pop elements
template<class ValueType>
class extractor
{
public:
friend auto connect<ValueType>(std::shared_ptr<base<typename identity<ValueType>::type>> ,
std::shared_ptr<extractor<ValueType>>);

void pop()
{
queue->pop();
}

private:
std::shared_ptr<std::queue<ValueType>> queue;
};


// A collection of replicated queues that allows only to push elements
template<class T = void*>
class base
{
public:

friend auto connect<T>(std::shared_ptr<base<typename identity<T>::type>>,
std::shared_ptr<extractor<T>>);

void push(const T& e)
{
for (auto & o : output)
{
o.second->push(e);
}
}

private:
std::unordered_map<std::shared_ptr<extractor<T>>,
std::shared_ptr<std::queue<T>>> output;
};


template<class T>
auto connect(std::shared_ptr<base<typename identity<T>::type>> node,
std::shared_ptr<extractor<T>> ext)
{
if (ext == nullptr)
{
ext.reset(new extractor<T>);
}

auto q = std::make_shared<std::queue<T>>();
node->output.emplace(ext, q);
ext->queue = q;
}


// A user type that puts number 42
class foo : public base<int>
{
public:

void do_something()
{
push(42);
}

};

// A user type that pops from an input
class bar : public base<>
{
public:
std::shared_ptr<extractor<int>> input;

void do_something_else()
{
input->pop();
}
};

int main(int argc, char** argv)
{
auto pusher = std::make_shared<foo>();
auto poper = std::make_shared<bar>();

// Here is the problem: I do not want client code to have to use "static_pointer_cast"
connect(std::static_pointer_cast<base<int>>(pusher), poper->input);

// Would like to be able to use:
connect(pusher, poper->input);

return 0;
}

关于c++ - 如何在使用派生实例调用模板基类的好友函数时避免使用 “std::static_pointer_cast”,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63751876/

30 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com