是什么原因导致它无法编译?它是声明签名还是在函数本身的实现中

What is causing this to fail to compile? Is it the declaration signature or is it within the implementation of the function itself?

本文关键字:函数 实现 声明 是什么 编译      更新时间:2023-10-16

我正在处理Component类的成员函数Component::connect()Component是我库中所有其他组件类型的抽象基类。

我现在正在修改这个方法,使用变分函数模板和SFINAE来允许未知的多个输入到这个函数中。。。所有输入都必须派生自Component类型。

我对它的声明和实现的语法有问题。。。我尝试了各种各样的方法,但却遇到了各种编译器错误。这可能与参数包扩展有关,或者我如何尝试在其签名中使用SFINAE有关。

这是我正在处理的类和函数的当前签名…


class Component {
protected:
std::string id_ = "";
std::list<std::shared_ptr<Component>> components_;
explicit Component(const std::string& id) : id_{ id } {}
public:
virtual ~Component() {}
std::string& id() { return id_; }
// Trying to use both Variadic Function Template and SFINAE for this function!
// I may eventually remove this from here and move it to another class using CRTP...
template<typename ... Args, std::enable_if_t <std::is_class<Args...>{}, Component> = 0 >
void connect(Args&& ...args) {
for (auto& l : components_) {
if (args->id_ == l->id()) {
std::cout << "Component " << (args->id_) << " already exists in " << id_ << "!n";
return;
}
}
components_.push_back( std::make_shared<Component>( args... ) );
std::cout << "Successfully connected " << args->id() << " to " << id_ << "n";
}
virtual std::list<std::shared_ptr<Component>> myConnections() { return components_; }
virtual void propagate() {};
}; 

使用C++17在Visual Studio 2017中成功编译此文件的正确语法是什么?我正在尝试使用SFINAE来利用这两个变分函数模板。


编辑

在我更改签名之前,从Component派生的派生类(如Wire(我可以这样使用它们:

Wire w1, w2, w3, w4;
w1.connect(&w2);
w1.connect(&w3);
w1.connect(&w4);
w2.connect(&w3);
w2.connect(&w4);

我想使用相同的功能,但以这种方式:

w1.connect(&w2, &w3, &w4);

这就是我想要使用变分函数模板的原因,也是我想要使用SFINAE来确保传递到::connect()中的任何类型(其中所有派生类都可以使用它(实际上都是从Component派生的!

不确定你到底想要什么(没有完整的例子更难(,但。。。

所有输入都必须从组件类型派生。

所以,如果我理解正确(并且给你标记了C++17,所以你可以使用折叠(,该方法的签名应该是

template <typename ... Args,
std::enable_if_t<(... && std::is_base_of<Component, Args>{}),
int> = 0>
void connect (Args && ... args)

或者

template <typename ... Args>
std::enable_if_t<(... && std::is_base_of<Component, Args>{})>
connect (Args && ... args)

我对它的声明和实现的语法有问题。。。

关于实现,我认为更大的问题是周期;也许你可以试试

for ( auto & l : components_ )
{
std::string  aid;
if ( true == ( ... || (args->id_ == l->id()
? (aid = args->id_, true)
: false) ) )
{
std::cout << "Component " << aid
<< " already exists in " << id_ << "!n";
return;
}
}

或者

for ( auto & l : components_ )
{
std::string  aid;
( ... , (args->id_ == l->id() ? aid = args->id_ : args->id_) );
if ( false == aid.empty() )
{
std::cout << "Component " << aid
<< " already exists in " << id_ << "!n";
return;
}
}

或者类似的东西。

但是关于

std::cout << "Successfully connected " << args->id() << " to " << id_ << "n";

坦率地说。。。我不知道。

error: expression contains unexpanded parameter pack 'args'
if (args->id_ == l->id()) {

您可以将connect()拆分为两个函数来处理当前未扩展的参数包。一个函数进行检查和连接,另一个函数使用折叠表达式:

template<typename T> // connect one only
void connect(T&& arg) {
static_assert(std::is_base_of_v<Component, std::remove_reference_t<T>>,
"Must be based on Component");
for (auto& l : components_) {
if (arg.id_ == l->id()) {
std::cout << "Component " << arg.id_ << " already in " << id_ << "n";
return;
}
}
components_.push_back( std::make_shared<Component>( std::forward<T>(arg) ) );
std::cout << "Successfully connected " << arg.id() << " to " << id_ << "n";
}
template<typename... Args> // folding
void connect(Args&& ...args) {
(connect(std::forward<Args>(args)), ...);
}

连接会这样做:

w1.connect(w2, w3, w4);

演示(使用您问题的旧修订版中的部分(