有没有办法强制用户显式指定模板参数类型?

Kir*_*rov 6 c++ templates

简短版本:我有一个模板函数,它是"通用的",但是我想强制用户显式指定参数的类型,它们作为参数传递给这个函数.

有任何想法吗?


长版:听起来像一个糟糕的设计,但这是我的情况,我现在想不出更好的东西.

我试图::setsockopt在一个小类中"实现" socket(我不想拥有大量的函数,采用不同的参数并做同样的事情).例如:

template< typename OPTION_VALUE_TYPE >
bool set_option( int level, int option_name, const OPTION_VALUE_TYPE& value )
{
    return -1 != ::setsockopt( fd_, level, option_name, &value, sizeof( value ) );
}
Run Code Online (Sandbox Code Playgroud)

但是,这可能会导致以下情况-调用set_option1,试图设置unsigned char选项将导致失败,因为1int.正确的用法是:

set_option< unsigned char >( level, option, 1 );
Run Code Online (Sandbox Code Playgroud)

set_option( level, option, 1 );
Run Code Online (Sandbox Code Playgroud)

将完全编译,但将是非常错误的.

小智 5

是的,您只需要以不能从参数推导出的方式使用模板参数.一种常见的方法是在模板类中使用typedef:

template <typename T>
struct identity {
  typedef T type;
};

template <typename OPTION_VALUE_TYPE>
bool set_option(int level, int option_name,
                typename identity<const OPTION_VALUE_TYPE&>::type value);
Run Code Online (Sandbox Code Playgroud)

要使用标准库中已存在的类型,您可以使用enable_if:

template <typename OPTION_VALUE_TYPE>
bool set_option(int level, int option_name,
                typename std::enable_if<true, const OPTION_VALUE_TYPE&>::type value);
Run Code Online (Sandbox Code Playgroud)

这个不允许类型参数推导的原因是因为编译器不能排除特殊化identity:编译器不能排除你在做什么

template <>
struct identity<U> { typedef V type; };
Run Code Online (Sandbox Code Playgroud)

哪里identity<U>::type不再是U.

  • 标准库中的其他选项是使用`typename add_const <T> :: type&`或`typename add_lvalue_reference <const T> :: type`,它们可能更清晰一些.使用`enable_if`可能会让人误以为有一些SFINAE参与其中. (2认同)
  • @JonathanWakely这是一个好点.另一方面,使用`add_const`或`add_lvalue_reference`并不能说明特殊情况正在发生,并且可能导致某人进行代码清理,认为可以通过拼写出`const OPTION_VALUE_TYPE&`来简化它.我认为两者都有待说明,我认为最清晰的方法是创建`identity`辅助类,而忽略标准库类型. (2认同)