将模板仿函数显式转换为特定仿函数
Explicit conversion of templated functors to specific functors
我有一个可调用结构 Foo
定义为
struct Foo {
template <typename T>
void operator()(T i) const { /* ... */ }
};
并且出于超出范围的原因,我想静态 select 调用它的类型,避免以下繁琐的符号:
Foo foo;
foo.operator()<int>(0);
foo.operator()<char>('0');
foo.operator()<char>(0); // Notice: I want to select the implementation
// so that **implicit conversions may take place**.
为此,我想实现一个模板成员函数To()
,以便上面可以重写为:
foo.To<int>()(0);
foo.To<char>()('0');
foo.To<char>()(0);
基本上,foo.To<T>()
会 return 一个可以用作回调的可调用对象。
一种方法可以通过使用 lambdas 来完成:
struct Foo {
template <typename T>
void operator()(T i) const { /* ... */ }
template <typename T>
auto To() const {
return [this](T i) -> void {
return this->operator()<T>(i);
};
}
};
但是,我不太喜欢这个解决方案,因为它创建了一个 lambda 并 return 按值对它进行运算,而我更喜欢 [=14= 的某种“静态转换” ] 与简单调用成员函数 相比, 没有计算开销。也可以采用 CRTP 解决方案,但它可能会为我希望更简单完成的事情添加太多样板代码。 实现上述目标的最有效方法是什么objective?
您关于涉及额外开销的假设不一定正确。编译器 确实 擅长优化事物,在花时间重构代码之前总是值得确认是否是这种情况,因为这将带来任何好处。
例证:
struct Foo {
template <typename T>
void operator()(T i) const;
template <typename T>
auto To() const {
return [this](T i) -> void {
return (*this)(i);
};
}
};
// Directly
void foo(const Foo& obj, char v) {
return obj(v);
}
auto bar(const Foo& obj, int v) {
return obj.To<char>()(v);
}
// As functors
auto get_foo_functor(const Foo& obj) {
return obj;
}
auto get_To_functor(const Foo& obj) {
return obj.To<char>();
}
Gcc 将其编译为
foo(Foo const&, char):
movsx esi, sil
jmp void Foo::operator()<char>(char) const
bar(Foo const&, int):
movsx esi, sil
jmp void Foo::operator()<char>(char) const
get_foo_functor(Foo const&):
xor eax, eax
ret
get_To_functor(Foo const&):
mov rax, rdi
ret
您可以在 godbolt 上现场试用示例:https://gcc.godbolt.org/z/jv6ejYn39
我有一个可调用结构 Foo
定义为
struct Foo {
template <typename T>
void operator()(T i) const { /* ... */ }
};
并且出于超出范围的原因,我想静态 select 调用它的类型,避免以下繁琐的符号:
Foo foo;
foo.operator()<int>(0);
foo.operator()<char>('0');
foo.operator()<char>(0); // Notice: I want to select the implementation
// so that **implicit conversions may take place**.
为此,我想实现一个模板成员函数To()
,以便上面可以重写为:
foo.To<int>()(0);
foo.To<char>()('0');
foo.To<char>()(0);
基本上,foo.To<T>()
会 return 一个可以用作回调的可调用对象。
一种方法可以通过使用 lambdas 来完成:
struct Foo {
template <typename T>
void operator()(T i) const { /* ... */ }
template <typename T>
auto To() const {
return [this](T i) -> void {
return this->operator()<T>(i);
};
}
};
但是,我不太喜欢这个解决方案,因为它创建了一个 lambda 并 return 按值对它进行运算,而我更喜欢 [=14= 的某种“静态转换” ] 与简单调用成员函数 相比, 没有计算开销。也可以采用 CRTP 解决方案,但它可能会为我希望更简单完成的事情添加太多样板代码。 实现上述目标的最有效方法是什么objective?
您关于涉及额外开销的假设不一定正确。编译器 确实 擅长优化事物,在花时间重构代码之前总是值得确认是否是这种情况,因为这将带来任何好处。
例证:
struct Foo {
template <typename T>
void operator()(T i) const;
template <typename T>
auto To() const {
return [this](T i) -> void {
return (*this)(i);
};
}
};
// Directly
void foo(const Foo& obj, char v) {
return obj(v);
}
auto bar(const Foo& obj, int v) {
return obj.To<char>()(v);
}
// As functors
auto get_foo_functor(const Foo& obj) {
return obj;
}
auto get_To_functor(const Foo& obj) {
return obj.To<char>();
}
Gcc 将其编译为
foo(Foo const&, char):
movsx esi, sil
jmp void Foo::operator()<char>(char) const
bar(Foo const&, int):
movsx esi, sil
jmp void Foo::operator()<char>(char) const
get_foo_functor(Foo const&):
xor eax, eax
ret
get_To_functor(Foo const&):
mov rax, rdi
ret
您可以在 godbolt 上现场试用示例:https://gcc.godbolt.org/z/jv6ejYn39