【问题标题】:Restriction of access to function [duplicate]限制访问功能[重复]
【发布时间】:2013-08-09 03:17:48
【问题描述】:

我有一个泛型类,我想在编译时只限制浮点类型的实例。如下例所示:

template <typename T>
class ClassName
{
    // instance variables, etc..

    void some_method()
    {
        // do stuff, but only for floating point types
    }
}

如何让编译器拒绝对非浮点类型的 ClassName 使用 some_method?

我一直在研究 SFINAE,但我根本无法让它发挥作用,所以在失败了几个小时后,我请求您的帮助。

谢谢:)

【问题讨论】:

  • 你试过什么?您可能可以将 std::is_floating_pointstd::enable_if 放在一起。
  • 目前我正在将函数包装在另一个函数中,如下所示:void some_other_method() { some_method(std::is_floating_point&lt;T&gt;()); } void some_method() { } 这可行,但我想要一个不必包装函数的解决方案。
  • @juanchopanza 如果您将some_method 设为模板,则可以使您的示例工作。我正在寻找一个先前的答案来解释这里所涉及的机制。
  • 模板专业化也是实现这一目标的有效技术。
  • @R.MartinhoFernandes 我修复了我的示例,但与此同时,其他人似乎也找到了相同的解决方案。

标签: c++ c++11 traits typetraits


【解决方案1】:

您可以使用std::is_floating_pointstd::enable_if 的组合来仅启用浮点类型的功能:

#include <type_traits>

template <typename T>
class ClassName
{
    // instance variables, etc..
 public:
  template<typename T2 = T,
           typename = typename std::enable_if< std::is_floating_point<T2>::value >::type>
  void some_method()
  { 
    // do stuff, but only for floating point types
  } 
};

int main()
{
  ClassName<double> d; // OK
  d.some_method();     // OK
  ClassName<int> i;    // OK
  i.some_method();     // ERROR
}

【讨论】:

  • @PetrBudnik 是第一个,但这个答案更详细,因此被接受。干杯!
【解决方案2】:

使用 static_assert,如果你的编译器支持 c++11

void some_method()
{
    static_assert( std::is_floating_point<T>::value, "Only for floating points" );
    // do stuff, but only for floating point types
}

如果你尝试对非浮点参数调用此方法,则会出现编译错误。

对于非浮点数:

static_assert( !std::is_floating_point<T>::value, "and only for non-floating point" );

【讨论】:

  • 你需要否定条件。
  • @jrok:谢谢,我编辑我的答案。
【解决方案3】:

类似这样的:

template< typename Tdummy = T, typename = typename std::enable_if< std::is_floating_point< Tdummy >::value >::type >
 void some_method()
{
}

编辑详细说明。这将导致以下结果。编译器将只为带有浮点模板参数的ClassName 生成some_method()。它不会为非浮动类型生成,并会导致编译时错误。

#include <type_traits>

template <typename T>
class ClassName
{
    // instance variables, etc..
    template< typename Tdummy = T, typename = typename std::enable_if< std::is_floating_point< Tdummy >::value >::type >
    void some_method()
    {
        // do stuff, but only for floating point types
    }

 void some_general_method
  {
   // general stuff for all types
  }
};

int main()
{
 ClassName< float > bar;
 ClassName< int > foo;

 bar.some_general_method(); // OK
 foo.some_general_method(); // OK

 bar.some_method(); // OK
 foo.some_method(); // Compile-time ERROR 

 return( 0 );
}

【讨论】:

  • 此模板中的 T == 类模板中的 T?
  • @Jesper 将其设为默认类型即可。我给出了一般的想法。请参阅编辑。
【解决方案4】:
void some_method(){

    if (std::is_floating_point<T>::value)
    {
        // do stuff, but only for floating point types
    }
    else
    {
        return;
    }
}

我也试过boost::is_floating_point :-

#include <boost/utility/enable_if.hpp>
#include <boost/type_traits/is_floating_point.hpp>

template <typename T>
class ClassName {
typename boost::enable_if<boost::is_floating_point<T> >::type
some_method(const T & t)
{

}
};

int main()
{
ClassName<float> p; //Compiles

/* Following throws error, 
error: no type named 'type' in 
    'struct boost::enable_if<boost::is_floating_point<int>, void>'
ClassName<int> q;
*/
}

【讨论】:

【解决方案5】:

As detailed in this answer,您需要将成员函数作为 SFINAE 工作的模板 (Live example at Coliru):

template <typename T>
class ClassName
{
    // instance variables, etc..

public:
    template <typename = typename std::enable_if<std::is_floating_point<T>::value>::type>
    void some_method()
    {
        // do stuff, but only for floating point types
    }
};

【讨论】:

    【解决方案6】:

    更新每 R. Martinho Fernandes 评论

    #include <type_traits>
    
    template <typename T>
    struct ClassName
    {
        // instance variables, etc..
    
        template<typename R = T>
        void some_method()
        {
            static_assert(std::is_floating_point<R>::value,
                "ClassName<T>::some_method is implemented only for floating "
                    "point T");
            // do stuff, but only for floating point types
        }
    };
    
    int main()
    {   
        ClassName<float> f;
        f.some_method();
        ClassName<int> i;
        i.some_method(); // <-- static_asserts here
        return 0;
    }
    

    【讨论】:

    • 如果您要断言与启用条件相反的情况,那么 SFINAE 是什么?
    • 当 SFINAE 选择 non-floating-point-T 变体,这应该是 barf,然后我断言 R(=T) is 浮点数。所以它会呕吐。
    • 当然,但是如果你只是将断言放在没有任何 SFINAE 的函数中,它也会出错。
    猜你喜欢
    • 2014-01-17
    • 1970-01-01
    • 2011-06-02
    • 2021-11-06
    • 1970-01-01
    • 2017-05-30
    • 2013-06-03
    • 1970-01-01
    相关资源
    最近更新 更多