C ++验证模板类型的可调用签名

时间:2016-06-28 04:32:13

标签: c++ templates

所以让我说我有一个像这样的通用函数:

template<typename TFunc>
void templFunc(TFunc func) {
    func(3, 6);
}

在编译时是否有任何方法可以验证TFunc的签名,无论它是std :: function还是lambda或任何类型的函数引用。我只想确保TFunc是签名void(int,int)或类似static_assert,所以我可以产生非垃圾错误消息。

3 个答案:

答案 0 :(得分:1)

所以我摆弄了一些type_traits的东西,我认为我有一些东西可以验证整个签名,而不仅仅是返回值,并且允许你创建易于读取的static_asserts,而不是签名时没有难以辨认的模板错误不配。这是一个糟糕的解决方案吗?

#include <functional>

template<typename, typename, typename = void>
struct is_signature : std::false_type {};

template<typename TFunc, typename Ret, typename... Args>
struct is_signature<TFunc, Ret(Args...),
        typename std::enable_if<
            std::is_convertible<
                TFunc,
                std::function<Ret(Args...)>
            >::value
        >::type
    > : public std::true_type
    {};

// works on both functions and lambda's
void blah(int, int) {
}

template<typename TFunc>
void templFunc(TFunc func) {
    static_assert(is_signature<TFunc, void(int, int)>::value, "Not gonna work! more info follows:");
    func(3, 6);
}

int main() {
    auto b = [](int, int) -> void {
    };

    auto c = [](int) -> void {
    };

    static_assert(is_signature<decltype(b), void(int, int)>::value, "b convertible to a std::function<void(int, int), so this checks out!");
    static_assert(is_signature<decltype(b), void(int)>::value, "b not convertible to a std::function<void(int)>, so this will error in compilation.");
    static_assert(is_signature<decltype(blah), void(int, int)>::value, "blah convertible to a std::function<void(int, int), so this checks out!");
    static_assert(is_signature<decltype(blah), void(int)>::value, "blah not convertible to a std::function<void(int)>, so this will error in compilation.");

    templFunc(b); // <- ok
    templFunc(c); // <- static assertion : not gonna work!
    return 0;
}

答案 1 :(得分:0)

您可以使用:

template<typename TFunc>
void templFunc(TFunc func) {
   static_assert(std::is_void<decltype(func(0,0))>::value,
                 "Bad template argument. The return type is not void");
   func(3, 6);
}
  1. 这将确保函数的返回类型为void
  2. 如果该函数没有采用两个参数,它将在调用func(3,6);中失败 - 两次。进入static_assert行,然后进入下一行。

  3. 如果int的参数类型或int可以提升,转换为或转换为int的任何其他类型,则函数调用将成功。确保参数类型为#include <type_traits> template<typename TFunc> void templFunc(TFunc func) { static_assert(std::is_void<decltype(func(0,0))>::value, "Bad template argument. The return type is not void"); func(3, 6); } void foo() { } void bar(int x, int y) { } int baz(int x, int y) { return 0; } struct Functor { void operator()(long, long) { } }; int main() { templFunc(foo); // Not OK. Two few arguments templFunc(bar); // OK templFunc(baz); // Not OK. Wrong return type templFunc([](int, int) -> void {} ); // OK templFunc(Functor()); // OK } 只需要一些额外的工作。我不确定那会带来什么。

  4. 测试程序:

       <com.samsoft.sam.Fab
            android:id="@+id/fab"
            app:layout_anchor="@id/asd"
            app:layout_anchorGravity="top|end"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" />
    

答案 2 :(得分:0)

这样的东西使用SFINAE(只有你根据模板参数做出断言;不完全确定原因,我认为这将是最有趣的部分:)):

#include <type_traits>

template<typename TFunc>
typename std::enable_if<std::is_same<typename std::result_of<TFunc(int, int)>::type, void>::value >::type templFunc(TFunc func)
{
  func(3, 6);
}

template<typename TFunc>
typename std::enable_if<!std::is_same<typename std::result_of<TFunc(int, int)>::type, void>::value >::type templFunc(TFunc func)
{
  static_assert(std::is_same<typename std::result_of<TFunc(int, int)>::type, void>::value, "error; invalid function");
}

auto a = [](int, int) {};
auto b = [](int x, int y) { return x + y; };

int main()
{
    templFunc(b);
    return 0;
}