【问题标题】:implicit instantiation of undefined template when instantiating alias of partial template spec实例化部分模板规范的别名时隐式实例化未定义模板
【发布时间】:2017-05-06 18:58:07
【问题描述】:

我正在遵循“实用 C++ 元编程”一书中的示例模板,并且已经到达示例的一部分,如果不绕过别名,我无法编译代码。当使用别名 ma​​ke_tuple_of_derefed_pa​​rams_t 时,我在定义时收到编译器错误“未定义模板的隐式实例化”。我可以使用部分模板特化 ma​​ke_tuple_of_derefed_pa​​rams 直接调用它,但不能使用别名。还有什么我需要做的吗?我在 clang++ 和 g++ 中都收到错误。

 template <typename F>
    class make_tuple_of_derefed_params;

template <typename Ret, typename... Args>
    struct make_tuple_of_derefed_params<Ret (Args...)>
{
    using type = std::tuple<std::remove_pointer_t<Args>...>;
};

template <typename F>
using make_tuple_of_derefed_params_t = typename make_tuple_of_derefed_params<F>::type;

完整代码为:

#include <numeric>
#include <iostream>
#include <type_traits>
#include <tuple>
#include <utility>
#include <time.h>

void adjust_values(double * alpha1,double * beta1,double * alpha2,double * beta2) { }

struct location {
    int x;
    int y;
};

class reading
{
    /* stuff */
    public:
    double alpha_value(location l, time_t t) const { return 1.5; }
    double beta_value(location l, time_t t) const { return 2.5; }
    /* other stuff */
};

 template <typename F>
    class make_tuple_of_derefed_params;

template <typename Ret, typename... Args>
    struct make_tuple_of_derefed_params<Ret (Args...)>
{
    using type = std::tuple<std::remove_pointer_t<Args>...>;
};

template <typename F>
using make_tuple_of_derefed_params_t = typename make_tuple_of_derefed_params<F>::type;

template <std::size_t FunctionIndex,typename FunctionsTuple,
        typename Params, std::size_t... I>
    auto dispatch_params(FunctionsTuple & functions,Params & params,
        std::index_sequence<I...>)
{
    return (std::get<FunctionIndex>(functions))(std::get<I>(params)...);
}

template <typename FunctionsTuple, std::size_t... I, typename Params,
            typename ParamsSeq>
    auto dispatch_functions(FunctionsTuple & functions,
            std::index_sequence<I...>, Params & params,
            ParamsSeq params_seq)
{
    return std::make_tuple(dispatch_params<I>(functions,params,params_seq)...);
}

template <typename LegacyFunction,typename... Functions,typename... Params>
    auto magic_wand(
        LegacyFunction legacy,
        const std::tuple<Functions...> & functions,
        const std::tuple<Params...> & params1,
        const std::tuple<Params...> & params2)
{
    static const std::size_t functions_count = sizeof...(Functions);
    static const std::size_t params_count = sizeof...(Params);

    make_tuple_of_derefed_params_t<LegacyFunction> params =

    std::tuple_cat(
        dispatch_functions(functions,
            std::make_index_sequence<functions_count>(),
            params1,
            std::make_index_sequence<params_count>()),
        dispatch_functions(functions,
            std::make_index_sequence<functions_count>(),
            params2,
            std::make_index_sequence<params_count>()));
    /* rest of the code */
    static constexpr auto t_count = 
        std::tuple_size<decltype(params)>::value;

    dispatch_to_c(  legacy, 
                    params,std::make_index_sequence<t_count>());
    return params;
}

template <typename Reading>
    std::tuple<double, double, double, double>
        get_adjusted_values(Reading & r,
            location l,
            time_t t1,
            time_t t2)
{
    return magic_wand(adjust_values,
                std::make_tuple(
                    [&r](location l, time_t t)
                    {
                        return r.alpha_value(l, t);
                    },
                    [&r](location l, time_t t)
                    {
                        return r.beta_value(l, t);
                    }),
                std::make_tuple(l, t1),
                std::make_tuple(l, t2)
            );
}


int main()
{
    reading r;
    location l { 1,2 };
    time_t epoch = 0;
    time_t seconds = time(NULL);

    std::tuple<double, double, double, double> ret2 = 
        get_adjusted_values(r, l, epoch, seconds);

    return 0;
}

【问题讨论】:

  • 您问题中的代码可以使用 clang 和 g++ 编译良好,即使添加一些琐碎的代码来实际使用您的别名也是如此。请发布一些真实的代码来演示您需要帮助的问题。
  • 你必须实例化它得到错误。我发布了完整的源代码。
  • 我确实实例化成功了。请注意,您在代码中遇到的错误是“error: implicit instantiation of undefined template 'make_tuple_of_derefed_params&lt;void (*)(double *, double *, double *, double *)&gt;'”——您正在使用指向函数的类型对其进行实例化,但您只为函数类型定义了它。

标签: c++ templates tuples partial specialization


【解决方案1】:

make_tuple_of_derefed_params 仅为函数类型定义。

template <typename F>
class make_tuple_of_derefed_params;

// Definition here, note that it only defines type for "T(Ts...)" template parameters.
template <typename Ret, typename... Args>
struct make_tuple_of_derefed_params<Ret (Args...)>
{
    using type = std::tuple<std::remove_pointer_t<Args>...>;
};

template <typename F>
using make_tuple_of_derefed_params_t = typename make_tuple_of_derefed_params<F>::type;

// ...

//make_tuple_of_derefed_params_t<int> foo;         // Error if uncommented.
make_tuple_of_derefed_params_t<int(int)> bar;      // Works.
//make_tuple_of_derefed_params_t<int(*)(int)> baz; // Error if uncommented.

要解决此问题,您需要为任何其他有效的Fs 提供定义。在这种特殊情况下,您需要定义F 何时是函数指针。

template <typename Ret, typename... Args>
struct make_tuple_of_derefed_params<Ret (*)(Args...)>
{
    using type = std::tuple<std::remove_pointer_t<Args>...>;
};

【讨论】:

  • 也就是说,dispatch_to_c 在您的扩展代码中未定义;我怀疑它是您为简洁而省略的“其余代码”的一部分。
  • 非常感谢。效果很好。我错过了'Ret (*)(Args...)。
  • @DavidRyan 不客气。如果需要,也可以使用类似的语法添加对函数引用和成员函数的支持。
【解决方案2】:

给定

template <typename T> void f(T);
void g();

f&lt;void()&gt;(g)f&lt;void(*)()&gt;(g)f&lt;void(&amp;)()&gt;(g) 这三个调用都是有效的。真的,f(g) 可以是其中任何一个。但是这个标准不得不强制一个,最终变成了f&lt;void(*)()&gt;(g)。这意味着当您随后将T 传递给另一个模板时,另一个模板需要能够处理指向函数的类型,或者您需要将指向函数的类型转换为函数类型。

这就是您的return magic_wand(adjust_values, ...) 呼叫发生的情况。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-09-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多