C++ 如何使否定一元与任何类型一起工作?

C++ 如何使否定一元与任何类型一起工作?,c++,stl,C++,Stl,以下问题: 我想创建一个操作符!可以使用从一元函数继承的任何函子。我试过: template<typename T> inline std::unary_negate<T> operator !( const T& pred ) { return std::not1( pred ); } 更新1 完整代码: #include <iostream> #include <functional> #include <utility>

以下问题:
我想创建一个操作符!可以使用从一元函数继承的任何函子。我试过:

template<typename T>
inline std::unary_negate<T> operator !( const T& pred ) {
 return std::not1( pred );
}
更新1
完整代码:

#include <iostream>
#include <functional>
#include <utility>
#include <cmath>
#include <algorithm>
#include <iterator>
#include <string>

#include <boost/assign.hpp>
#include <boost/assign/std/vector.hpp>
#include <boost/assign/std/map.hpp>
#include <boost/assign/std/set.hpp>
#include <boost/assign/std/list.hpp>
#include <boost/assign/std/stack.hpp>
#include <boost/assign/std/deque.hpp>

struct is_prime : std::unary_function<int, bool> {
 bool operator()( int n ) const {
  if( n < 2 )
   return 0;
  if( n == 2 || n == 3 )
   return 1;
  if( n % 2 == 0 || n % 3 == 0 )
   return 0;
  int upper_bound = std::sqrt( static_cast<double>( n ) );
  for( int pf = 5, step = 2; pf <= upper_bound; ) {
   if( n % pf == 0 )
    return 0;
   pf  += step;
   step = 6 - step;
  }
  return 1;
 }
};

/*
template<typename T>
inline std::unary_negate<T> operator !( const T& pred, typename T::argument_type* dummy = 0 ) {
 return std::not1<T>( pred );
}
*/

inline std::unary_negate<is_prime> operator !( const is_prime& pred ) {
 return std::not1( pred );
}

template<typename T>
inline void print_con( const T& con, const std::string& ms = "", const std::string& sep = ", " ) {
 std::cout << ms << '\n';
 std::copy( con.begin(), con.end(), std::ostream_iterator<typename T::value_type>( std::cout, sep.c_str() ) );
 std::cout << "\n\n";
}

int main() {
 using namespace boost::assign;
 std::vector<int> nums;
 nums += 1, 3, 5, 7, 9;
 nums.erase( remove_if( nums.begin(), nums.end(), !is_prime() ), nums.end() );
 print_con( nums, "After remove all primes" ); 
}
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
结构是素数:std::一元函数{
布尔运算符()(整数n)常量{
if(n<2)
返回0;
如果(n==2 | | n==3)
返回1;
如果(n%2==0 | | n%3==0)
返回0;
int上界=std::sqrt(static_cast(n));

对于(int-pf=5,step=2;pf我不知道您到底在编译什么,但我怀疑您使用的std::一元函数没有所需的模板参数,不是吗


你能显示完整的代码吗?< /p> 你所得到的模糊错误是C++模板错误的经典例子。它试图说的是你试图调用<代码>操作符!

函数的类型不兼容。
std::一元否定
希望其模板参数具有
参数类型
typedef,而传递给函数的对象没有此typedef


也就是说,我不确定您想要实现什么。标准库已经有了此功能,尽管名称不同:
std::not1()
。您为什么要包装它?用户确切地知道什么是
std::not1(f)
的意思是,但在我看来,就用户在给定上下文中可能期望的内容而言,f似乎是一个陷阱。

这里有一种基于“替换失败不是错误”(SFINAE)的方法这说明在过载解决过程中,如果C++编译器尝试实例化模板并遇到问题,它不会触发编译错误。相反,它只是从考虑中移除特定模板。(也就是说,有许多不同的函数具有相同的名称,但参数不同),其中有些是模板,有些不是,如果其中一个候选模板函数没有意义,您将永远不会得到编译器错误

这个特殊的技术可以通过两种不同的方式来帮助您解决这个问题。首先,假设现在我有一个名为“IsAdaptable”的黑盒子它可以查看一个类型并告诉我某个特定类型是否是可适应的函数。根据这些信息,我们如何使您的
运算符!
函数只适用于可适应的类型?好的,使用SFINAE原则,我们需要在输入类型为无法适应。有很多方法可以做到这一点,但有一种常用的方法使用名为“启用if”的帮助器模板。以下是启用if模板的完整实现:

template <bool Condition, typename T> struct EnableIf {
     typedef T type;
};
template <typename T> struct EnableIf<false, T> {
     // Empty
};
但是,只有当某个谓词“predicate”对类型T有效时,您才希望此函数可用。然后您可以将函数更改为如下所示:

template <typename T>
typename EnableIf<Predicate<T>::value, ActualReturnType>::type MyFunction(/* ... arguments ... */) {
    /* ... body here ... */
}
template <typename Pred>
typename EnableIf<IsAdaptable<Pred>::value, std::unary_negate<Pred> >::type
operator! (const Pred& p) {
     return std::not1(p);
}
这使用了上面的技巧来表示“此
运算符!
函数仅适用于可适应函数的类型。”我们现在已经完成了一半-给定了
IsAdaptable
的实现,我们就完成了

问题是,写
IsAdaptable
一点都不容易。它最终使用了一系列可怕的黑客手段,会让你哭泣。但不要害怕!一旦你看到了大局,就不难理解了

我们使
IsAdaptable
工作的方法是以一种全新的方式使用SFINAE。下面是这个想法的概要。假设我们有两个函数是另一个函数的重载,其中一个函数返回一个名为“Yes”的类型,另一个函数返回一个名为“No”的类型。然后我们编写这些函数,使版本始终优先于“否”版本,但“是”版本仅在某些给定类型可适应时才可用。在这种情况下,调用函数时,以下两种情况之一为真:

  • 所讨论的类型是可适应的。在这种情况下,函数的两个版本都可用,但“是”版本优先于“否”版本,因此调用“是”版本
  • 所讨论的类型是不可适应的。在这种情况下,唯一可用的函数版本是“否”版本,因此这就是调用的版本。 但是你怎么能构造这样的函数呢?事实证明有一个聪明但并不特别复杂的解决方案:

    template <typename T> Yes TestFunction(typename T::argument_type* argument);
    template <typename T> No  TestFunction(...);
    
    <> P> >此函数的第一个版本仅在>T/< C++ >内有一个名为AgMuthType类型嵌套的类型。第二个版本总是可用的。永远不会在参数列表更具体的函数上选择。因此,如果
    T
    中嵌套了
    argument\u type
    ,则上述表达式的类型为
    Yes
    ,否则类型为
    No
    。我们就快到了-如果我们能够以某种方式检测返回类型,我们就要进行测试了查看
    T
    是否适用

    我们完成最后一步的方法有点迂回。我们将定义类型
    Yes
    No
    ,使它们具有不同的大小:

    typedef char Yes;
    struct No {
        char dummy[32];
    };
    
    现在我们知道
    sizeof(Yes)==1
    sizeof(No)>1
    。将所有这些结合在一起,我们得到了
    的最终版本是可适应的:

    template <typename T> struct IsAdaptable {
    private:
        typedef char Yes;
        struct No {
             char dummy[32];
        };
    
        template <typename U> static Yes test(typename U::argument_type*);
        template <typename U> static No  test(...);
    
    public:
        static const bool value = (sizeof(test<T>(0)) == sizeof(Yes));
    };
    

    希望这有帮助!

    我不知道TR1的东西是否更好(我希望如此),但是boost bind对于这类东西更容易使用100倍。我会看看。这段代码在g++中没有引起任何问题。也许代码中还有其他东西?如果你说
    return std::not1(pred),会发生什么;
    ?@wilhelmtell:谢谢,但是VS给出了与上述相同的错误。@Chan:是的,唐
    template <typename T> Yes TestFunction(typename T::argument_type* argument);
    template <typename T> No  TestFunction(...);
    
    TestFunction<T>(NULL);
    
    typedef char Yes;
    struct No {
        char dummy[32];
    };
    
    template <typename T> struct IsAdaptable {
    private:
        typedef char Yes;
        struct No {
             char dummy[32];
        };
    
        template <typename U> static Yes test(typename U::argument_type*);
        template <typename U> static No  test(...);
    
    public:
        static const bool value = (sizeof(test<T>(0)) == sizeof(Yes));
    };
    
    template <bool cond, typename T> struct EnableIf {
      typedef T type;
    };
    template <typename T> struct EnableIf<false, T> {
    
    };
    
    template <typename T> struct IsAdaptable {
    private:
      typedef char Yes;
      struct No {
        char buffer[32];
      };
    
      template <typename U> static Yes test(typename U::argument_type*);
      template <typename U> static No  test(...);
    
    public:
      static const bool result = (sizeof(test<T>(0)) == sizeof(Yes));
    };
    
    template<typename T>                                                                                                                                           
    inline typename EnableIf<IsAdaptable<T>::result, std::unary_negate<T> >::type operator !(const T& pred) {                                                      
      return std::not1( pred );                                                                                                                                    
    }