C++ 如何使此模板参数可变?

C++ 如何使此模板参数可变?,c++,C++,假设我有这样一个模板声明: template <class A, class B, class C = A (&)(B)> 但直到最后一部分,我收到了错误消息。我认为我做得不对。我做错了什么?模板 template <typename T> struct helper; template <typename F, typename B> struct helper<F(B)> { typedef F (*type)(B); };

假设我有这样一个模板声明:

template <class A, class B, class C = A (&)(B)>
但直到最后一部分,我收到了错误消息。我认为我做得不对。我做错了什么?

模板
template <typename T>
struct helper;

template <typename F, typename B>
struct helper<F(B)> {
    typedef F (*type)(B);
};

template<class F, class B>
void f()
{
}

template <class F, class B, typename... C>
void f(typename helper<F(B)>::type x, C... c)
{
    std::cout << x(B(10)) << '\n';
    f<F,B>(c...);
}

int identity(int i) { return i; }
int half(int i) { return i/2; }
int square(int i) { return i * i; }
int cube(int i) { return i * i * i; }

int main()
{
    f<int,int>(identity,half,square,cube);
}
结构助手; 模板 结构辅助程序{ 类型定义F(*类型)(B); }; 模板 void f() { } 模板 void f(typename助手::type x,C…C) {
std::cout我认为您可以使用以下方法。首先,类型特征的一些机制。这允许您确定参数包中的类型是否相同(我猜您希望所有函数都具有相同的签名):

最后,如果你需要一个灵感,告诉你一旦你有了这个参数包,该怎么做,你可以检查一下(这个答案中使用的机器的哪一部分)。调用参数包
F…F
中所有函数的简单方法如下(归功于@MarkGlisse):

initializer_list{(f(forward(arg)),0);
您可以轻松地将其包装在宏中(只需查看Mark对我发布的链接的回答)

这是一个完整的可编译程序:

#include <iostream>
#include <type_traits>

using namespace std;

struct null_type { };

// Declare primary template
template<typename... Ts>
struct homogeneous_type;

// Base step
template<typename T>
struct homogeneous_type<T>
{
    using type = T;
    static const bool isHomogeneous = true;
};

// Induction step
template<typename T, typename... Ts>
struct homogeneous_type<T, Ts...>
{
    // The underlying type of the tail of the parameter pack
    using type_of_remaining_parameters = typename
        homogeneous_type<Ts...>::type;

    // True if each parameter in the pack has the same type
    static const bool isHomogeneous =
        is_same<T, type_of_remaining_parameters>::value;

    // If isHomogeneous is "false", the underlying type is a fictitious type
    using type = typename conditional<isHomogeneous, T, null_type>::type;
};

// Meta-function to determine if a parameter pack is homogeneous
template<typename... Ts>
struct is_homogeneous_pack
{
    static const bool value = homogeneous_type<Ts...>::isHomogeneous;
};

template<typename T>
struct signature;

template<typename A, typename B>
struct signature<A (&)(B)>
{
    using ret_type = A;
    using arg_type = B;
};

template <typename F>
void foo(F&& f)
{
    cout << f(42) << endl;
}

template <typename... F>
void foo(typename homogeneous_type<F...>::type f, F&&... fs)
{
    static_assert(is_homogeneous_pack<F...>::value, "Not homogeneous!");
    using fxn_type = typename homogeneous_type<F...>::type;

    // This was template parameter A in your original code
    using ret_type = typename signature<fxn_type>::ret_type;

    // This was template parameter B in your original code
    using arg_type = typename signature<fxn_type>::arg_type;

    cout << f(42) << endl;
    foo(fs...);
}

int fxn1(double i) { return i + 1; }
int fxn2(double i) { return i * 2; }
int fxn3(double i) { return i / 2; }
int fxn4(string s) { return 0; }

int main()
{
    foo(fxn1, fxn2, fxn3); // OK

    // foo(fxn1, fxn2, fxn4); // ERROR! not homogeneous signatures

    return 0;
}
#包括
#包括
使用名称空间std;
结构null_类型{};
//声明主模板
模板
结构齐次型;
//基本台阶
模板
结构齐次型
{
使用类型=T;
静态常数bool isHomogeneous=true;
};
//诱导步骤
模板
结构齐次型
{
//参数包尾部的基础类型
使用剩余参数的类型=类型名
同质类型::类型;
//如果包中的每个参数具有相同的类型,则为True
静态常数布尔非齐次=
是相同的::值;
//如果isHomogeneous为“false”,则基础类型为虚构类型
使用type=typename条件::type;
};
//确定参数包是否为齐次的元函数
模板
结构是齐次的
{
静态常量布尔值=齐次类型::isHomogeneous;
};
模板
结构签名;
模板
结构签名
{
使用ret_类型=A;
使用arg_type=B;
};
模板
无效foo(F&F)
{

如果你只使用
模板
?获取任何东西,并使用
启用\u if
和traits类进行验证,那会怎么样?事实上,获取任何东西似乎都是一个更好的方法。这仍然不是我要问的。我想要一个可变的函数指针列表,我可以在函数内部调用。这不能做到这一点。@BenjaminLindley:但不是他的方法强迫您显式地指定模板参数,对吗?它无法推断them@BenjaminLindley:因此,由于所有函数最终都必须具有相同的签名,并且我的解决方案可以从参数中推断出来,我会说我的方法更好……我错了吗?@AndyProwl:可能吧。不幸的是,我无法编译您的代码。你介意提供一个完整的连续可编译列表吗?@BenjaminLindley:当然,我会这样做,并将其添加到我的回答中。这确实很好,但并不是说我希望所有方法都是同构的。它们可能是different@templateboy:谢谢,但我可能错过了一些东西。它们怎么会不一样呢?即使是在你接受的解决方案是可以的,而且你必须明确地提供SignatureEYP,我也被这句话弄糊涂了。我想这就是“我该怎么做才能拥有数量可变的C型对象”的意思。好吧,别介意最后那句话。你是对的,我确实这么说了。
template<class F, class B>
void f(F(*x)(B))
{
    x(B());
}

template <class F, class B, typename... C>
void f(F(*x)(B), C... c)
{
    f(x);
    f<F,B>(c...);
}

int identity(int i) { return i; }
int half(int i) { return i/2; }
int square(int i) { return i * i; }
int cube(int i) { return i * i * i; }
int string_to_int(std::string) { return 42; }

int main()
{
    f(identity,half,square,cube);
    // f(identity,half,string_to_int);
}
struct null_type { };

// Declare primary template
template<typename... Ts>
struct homogeneous_type;

// Base step
template<typename T>
struct homogeneous_type<T>
{
    using type = T;
    static const bool isHomogeneous = true;
};

// Induction step
template<typename T, typename... Ts>
struct homogeneous_type<T, Ts...>
{
    // The underlying type of the tail of the parameter pack
    using type_of_remaining_parameters = typename 
        homogeneous_type<Ts...>::type;

    // True if each parameter in the pack has the same type
    static const bool isHomogeneous = 
        is_same<T, type_of_remaining_parameters>::value;

    // If isHomogeneous is "false", the underlying type is a fictitious type
    using type = typename conditional<isHomogeneous, T, null_type>::type;
};

// Meta-function to determine if a parameter pack is homogeneous
template<typename... Ts>
struct is_homogeneous_pack
{
    static const bool value = homogeneous_type<Ts...>::isHomogeneous;
};
template<typename T>
struct signature;

template<typename A, typename B>
struct signature<A (&)(B)>
{
    using ret_type = A;
    using arg_type = B;
};
template <typename... F>
void foo(F&&... f)
{
    static_assert(is_homogeneous_pack<F...>::value, "Not homogeneous!");
    using fxn_type = typename homogeneous_type<F...>::type;

    // This was template parameter A in your original code
    using ret_type = typename signature<fxn_type>::ret_type;

    // This was template parameter B in your original code
    using arg_type = typename signature<fxn_type>::arg_type;

    // ...
}
int fxn1(double) { }
int fxn2(double) { }
int fxn3(string) { }

int main()
{
    foo(fxn1, fxn2); // OK
    foo(fxn1, fxn2, fxn3); // ERROR! not homogeneous signatures
    return 0;
}
initializer_list<int>{(f(forward<ArgType>(arg)), 0)...};
#include <iostream>
#include <type_traits>

using namespace std;

struct null_type { };

// Declare primary template
template<typename... Ts>
struct homogeneous_type;

// Base step
template<typename T>
struct homogeneous_type<T>
{
    using type = T;
    static const bool isHomogeneous = true;
};

// Induction step
template<typename T, typename... Ts>
struct homogeneous_type<T, Ts...>
{
    // The underlying type of the tail of the parameter pack
    using type_of_remaining_parameters = typename
        homogeneous_type<Ts...>::type;

    // True if each parameter in the pack has the same type
    static const bool isHomogeneous =
        is_same<T, type_of_remaining_parameters>::value;

    // If isHomogeneous is "false", the underlying type is a fictitious type
    using type = typename conditional<isHomogeneous, T, null_type>::type;
};

// Meta-function to determine if a parameter pack is homogeneous
template<typename... Ts>
struct is_homogeneous_pack
{
    static const bool value = homogeneous_type<Ts...>::isHomogeneous;
};

template<typename T>
struct signature;

template<typename A, typename B>
struct signature<A (&)(B)>
{
    using ret_type = A;
    using arg_type = B;
};

template <typename F>
void foo(F&& f)
{
    cout << f(42) << endl;
}

template <typename... F>
void foo(typename homogeneous_type<F...>::type f, F&&... fs)
{
    static_assert(is_homogeneous_pack<F...>::value, "Not homogeneous!");
    using fxn_type = typename homogeneous_type<F...>::type;

    // This was template parameter A in your original code
    using ret_type = typename signature<fxn_type>::ret_type;

    // This was template parameter B in your original code
    using arg_type = typename signature<fxn_type>::arg_type;

    cout << f(42) << endl;
    foo(fs...);
}

int fxn1(double i) { return i + 1; }
int fxn2(double i) { return i * 2; }
int fxn3(double i) { return i / 2; }
int fxn4(string s) { return 0; }

int main()
{
    foo(fxn1, fxn2, fxn3); // OK

    // foo(fxn1, fxn2, fxn4); // ERROR! not homogeneous signatures

    return 0;
}