在类模板中调用模板化函子

Calling a templated functor in a class template

本文关键字:调用      更新时间:2023-10-16

有没有办法调用类模板Foo的函子operator()( int ),如下所示(在线版本)

template<typename T>
struct Foo
{
    template<typename U>
    void operator()( int )
    {
    }
};
int main(int argc, char *argv[])
{
    Foo<char> foo;
    foo<bool>( 42 );
}

我在 gcc 4.9.3 中收到错误消息

error: expected primary-expression before ‘bool’
  foo<bool>( 42 );

如果成员函数不是函子并且前缀为 ::.->,我会在函子前面加上 template。如果没有一些帮助,编译器就不知道如何解析这个表达式;作为 foo<int> 类型的匿名对象的函子或实例化。

它可以与;

foo.operator()<bool>( 42 );

运算符最适合使用推导的模板参数类型。

您没有提供足够的详细信息来说明使用它的上下文,作为您可以考虑的替代方案;

  • 使调用运算符成为成员函数,从而允许显式模板类型参数
  • 标签调度机制
  • 接受类型 U 作为参数

例如;

template<typename U>
void operator()( int, U&& /*initial*/ )
{
  // use the initial value of U
}
// called as...
foo(42, true); // U is bool in your example

或者只是成员函数;

template<typename U>
void my_func( int )
{
}
// called as...
foo.my_fun<bool>( 42 );

是的,但它很丑陋:

foo.operator()<bool>( 42 );

不幸的是,您需要为此使用foo.operator()<bool>(42);foo<bool> 对 C++14 变量模板等内容有效,而不是模板调用运算符。

您可以做的是标记类型并将其作为参数传递给调用运算符以推断正确的类型:

//tag
template <typename T>
struct type{};
template<typename T>
struct Foo
{
    template<typename U>
    //deduction on the tagged type
    void operator()( type<U>, int )
    {
    }
};
int main(int argc, char *argv[])
{
    Foo<char> foo;
    foo( type<bool>{}, 42 );
    //   ^^^^^^^^^^^^ pass tag
}

您可以使用标签的 C++14 个变量模板来使其更好一些:

template <typename T>
struct type_t{};
//variable template for nicer usage
template <typename T>
type_t<T> type;
template<typename T>
struct Foo
{
    template<typename U>
    void operator()( type_t<U>, int )
    {
    }
};
int main(int argc, char *argv[])
{
    Foo<char> foo;
    foo( type<bool>, 42 );
    //don't need {}^
}

可悲的是,如果函子本身是一个模板,语法会变得更加复杂。以下操作将失败:

template <typename Functor, typename ... Args>
void Foo (Functor & f)
{
    f.operator()<Args...>();
}
struct MyFunctor
{
    template <typename ...>
    void operator () () {}
};
int main ()
{
    MyFunctor f;
    Foo(f);
}

相反,我们必须写:

f.template operator()<Args...>();