c – 用于测试func(args)是否格式正确并且具有所需返回类型的特征

有许多类似的问题/答案,但我无法将这些答案放在一起以达到我的目的.我想要一个特质

template<typename Func, typename ReturnType, typename... Args>
struct returns_a { static const bool value; };

这样的

returns_a<F,T,Args>::value

如果F(Args)形成良好并返回T,则为真.经过一些研究,我得到了如下工作:

// value is true if Func(Args...) is well formed
template<typename Func, typename... Args>
class is_callable
{
  template <typename F>
  static decltype(std::declval<F>()(std::declval<Args>()...), void(), 0) test(int);
  template <typename>
  static void test(...);
public:
  static const bool value = !std::is_void<decltype(test<Func>(0))>::value;
};

// return_type<FunctionSignature>::type is the return type of the Function
template<typename>
struct return_type {};

template<typename ReturnType, typename... Args>
struct return_type<ReturnType(Args...)>
{ typedef ReturnType type; };

// helper class, required to use SFINAE together with variadic templates parameter
// generic case: Func(Args...) is not well-defined
template <typename Func, typename ReturnType, typename dummy, typename... Args>
struct returns_a_helper { static const bool value = false; };

// Func is a function signature
template <typename Func, typename ReturnType, typename... Args>
struct returns_a_helper<Func, ReturnType, typename
                        std::enable_if<std::is_function<Func>::value>::type, Args...>
{
  static const bool value =
    std::is_convertible<typename return_type<Func>::type,
                        ReturnType>::value;

};

// Func(Args...) not a function call, but well-defined 
template <typename Func, typename ReturnType, typename... Args>
struct returns_a_helper<Func,ReturnType,typename
                        std::enable_if<is_callable<Func>::value &&
                       !std::is_function<Func>::value
                                      >::type, Args...>
{
  static const bool value =
    std::is_convertible<typename std::result_of<Func(Args...)>::type,
                ReturnType>::value;
};

template <typename Func, typename ReturnType, typename... Args>
struct returns_a : returns_a_helper<Func, ReturnType, void, Args...> {};

现在适用于仿函数和函数.这是一个简单的测试:

struct base { virtual bool member(int) const = 0; };
struct foo : base { bool member(int x) const { return x&2; } };
struct bar { foo operator()() { return foo(); } };
foo free_function() { return foo(); }

template<typename T, typename Func>
void test(Func const&func)
{
   std::cout << std::boolalpha << returns_a<Func,T>::value << std::endl;
}

int main()
{
   foo x;
   bar m;
   test<const base&>([&]() { return x; });
   test<const base&>(m);
   test<const base&>(free_function);
   return 0;
}

嗯,这有效,但似乎有点麻烦.任何人都有更好/更优雅/更短的解决方案?

最佳答案 我想这会做: –

(更正了包括aschepler的测试用例)

#include <type_traits>

template<typename Func, typename Ret, typename... Args>
struct returns_a
{   
    template<typename F, typename ...As>
    static constexpr bool test(
        decltype(std::declval<F>()(std::declval<As>()...)) * prt) {
        return std::is_same<Ret *,decltype(prt)>::value;
    }

    template <typename F, typename ...As>
    static constexpr bool test(...) {
        return false; 
    }

    static const bool value = test<Func,Args...>(static_cast<Ret *>(0)); 
};

// Testing...

#include <iostream>

void fn0();
int fn1(int);
int fn2(int,int);
struct cls{};
struct fntor
{
    int operator()(int i) { return 1; }
};
auto lamb0 = [](int i) -> int { return i; };
struct B {}; 
struct D : public B {};
auto lamb1 = []{ return B{}; }; 

int main()
{
    std::cout << returns_a<decltype(fn0),void>::value << std::endl; // 1
    std::cout << returns_a<decltype(fn1),int,int>::value << std::endl; // 1
    std::cout << returns_a<decltype(fn1),int,double>::value << std::endl; // 1
    std::cout << returns_a<decltype(fn1),double,int>::value << std::endl; // 0
    std::cout << returns_a<decltype(fn1),char,int>::value << std::endl; // 0
    std::cout << returns_a<decltype(fn1),unsigned,int>::value << std::endl; // 0
    std::cout << returns_a<decltype(fn2),int,int,int>::value << std::endl; // 1
    std::cout << returns_a<decltype(fn2),int,char,float>::value << std::endl; // 1
    std::cout << returns_a<cls,int,int>::value << std::endl; // 0
    std::cout << returns_a<fntor,int,int>::value << std::endl; // 1
    std::cout << returns_a<decltype(lamb0),int,int>::value << std::endl; // 1
    std::cout << returns_a<double,int,int>::value << std::endl; // 0
    std::cout << returns_a<decltype(lamb1), D>::value << std::endl; //0
    return 0;
}

(用clang 3.2,gcc 4.7.2,gcc 4.8.1构建)

点赞