Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/156.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 在模板生成器模式中分解重复的构造函数调用_C++_C++11_Templates_Builder - Fatal编程技术网

C++ 在模板生成器模式中分解重复的构造函数调用

C++ 在模板生成器模式中分解重复的构造函数调用,c++,c++11,templates,builder,C++,C++11,Templates,Builder,考虑下面的类,它最终允许我为成员变量构造一个具有特定(运行时)值的对象,并嵌入一些由几个(编译时)类型携带的行为 同一个构建允许更新成员变量(通常的构建器模式),以及更改与构建器的类型状态相关联的模板类型参数(仅显示两个模板类型参数和成员,但在实践中,会有更多): 然后每个with t*方法都可以调用copy 但是,我不清楚如何避免在调用中包含完全限定类型的Builder: template <typename T1_NEW> Builder<T1_NEW, T2 >

考虑下面的类,它最终允许我为成员变量构造一个具有特定(运行时)值的对象,并嵌入一些由几个(编译时)类型携带的行为

同一个构建允许更新成员变量(通常的构建器模式),以及更改与构建器的类型状态相关联的模板类型参数(仅显示两个模板类型参数和成员,但在实践中,会有更多):

然后每个
with t*
方法都可以调用copy

但是,我不清楚如何避免在调用中包含完全限定类型的
Builder

template <typename T1_NEW>
Builder<T1_NEW, T2   > withT1() { return copy<T1_NEW, T2>(); }
模板
生成器withT1(){return copy();}
这里的治疗方法比原来的毒药更糟糕,因为我需要用
限定每个副本调用(这对于每个
使用t*
方法是不同的)。是否有某种方法可以引用返回类型或其他类型的推断,我可以使用它们在每个函数中以相同的方式调用
copy()


我是用C++11编写的,但也欢迎讨论如何在以后的标准中改进C++11解决方案。

我不确定我是否100%理解了您的问题。无论如何,让我尝试一个试探性的答案: 我在您的代码片段中添加了一个模板化隐式转换运算符,该运算符正在调用reinterpret_cast

template<typename U1, typename U2>
operator Builder<U1, U2>(){ return *reinterpret_cast<Builder<U1, U2>*>(this); }
模板
运算符生成器(){return*reinterpret_cast(this);}
这通常是黑客和不安全的,但在你的情况下,它做的工作。它允许withT1和withT2成员函数类似

template <typename T1_NEW>
Builder<T1_NEW, T2   > withT1() { return *this; }

template <typename T2_NEW>
Builder<T1   , T2_NEW> withT2() { return *this; }
模板
生成器withT1(){return*this;}
模板
生成器withT2(){return*this;}
我用来测试代码的代码片段附在下面

#include <type_traits>

template<typename T1, typename T2>
struct Foo;

template<>
struct Foo<int, double>{
    int mInt;
    double mDouble;
};

template<>
struct Foo<char, double>{
    char mChar;
    double mDouble;
};

struct t1{
    using type = int;
    static type member;
};

struct t2{
    using type = double;
    static type another;
};

struct tt1{
    using type = char;
    static type member;
};

template <typename T1 = t1, typename T2 = t2>
class Builder {
  // int param1, param2;
  Builder(int param1, int param2) : param1{param1}, param2{param2} {}
public:
  int param1, param2;
  Builder() : Builder(0, 0) {}

  template<typename U1, typename U2>
  operator Builder<U1, U2>(){ return *reinterpret_cast<Builder<U1, U2>*>(this); }

  template <typename T1_NEW>
  Builder<T1_NEW, T2   > withT1() { return *this; }

  template <typename T2_NEW>
  Builder<T1   , T2_NEW> withT2() { return *this; }

  Foo<typename T1::type, typename T2::type> make() {
    // uses T1 and T2 to populate members of foo
    return Foo<typename T1::type, typename T2::type>{T1::member, T2::another};
  }
};


int main(){
Builder<t1, t2> b;
auto c = b.withT1<tt1>();
static_assert(std::is_same<decltype(c), Builder<tt1, t2>>::value, "error");
}
#包括
模板
结构Foo;
模板
结构Foo{
国际铸币厂;
双倍;
};
模板
结构Foo{
查尔·麦克哈尔;
双倍;
};
结构t1{
使用type=int;
静态型构件;
};
结构t2{
使用类型=双;
静态型另一;
};
结构tt1{
使用type=char;
静态型构件;
};
模板
类生成器{
//int param1,param2;
生成器(int-param1,int-param2):param1{param1},param2{param2}{
公众:
int param1,param2;
Builder():Builder(0,0){}
模板
运算符生成器(){return*reinterpret_cast(this);}
模板
生成器withT1(){return*this;}
模板
生成器withT2(){return*this;}
富美{
//使用T1和T2填充foo的成员
返回Foo{T1::member,T2::other};
}
};
int main(){
建筑商b;
自动c=b,带T1();
静态断言(std::is_same::value,“error”);
}

您可以引入一个具有隐式转换的生成器代理,以节省键入的时间:

template<typename T1, typename T2>
struct Builder;

struct BuilderProxy
{
    int param1, param2;

    template<typename T1, typename T2>
    operator Builder<T1, T2>() const { return {param1, param2}; }
};

template <typename T1, typename T2>
struct Builder {
    int param1, param2;
    Builder(int param1, int param2) : param1{param1}, param2{param2} {}

    BuilderProxy copy() { return {param1, param2}; }

    template <typename T1_NEW>
    Builder<T1_NEW, T2   > withT1() { return copy(); }

    template <typename T2_NEW>
    Builder<T1   , T2_NEW> withT2() { return copy(); }
};

int main() {
    Builder<int, int> a(1, 2);
    Builder<double, double> b = a.withT1<double>().withT2<double>();
}
模板
结构生成器;
结构构建程序
{
int param1,param2;
模板
运算符生成器()常量{return{param1,param2};}
};
模板
结构生成器{
int param1,param2;
生成器(int-param1,int-param2):param1{param1},param2{param2}{
BuilderProxy copy(){return{param1,param2};}
模板
生成器withT1(){return copy();}
模板
生成器withT2(){return copy();}
};
int main(){
建筑商a(1,2);
生成器b=a.带T1().带T2();
}

我没有C++11的解决方案,但正如您自己所说,C++14可能对其他人有帮助

如果我理解正确的话,您需要一个存储任意参数的类,该类以一种方便的方式将所有参数传递给构造函数。这可以使用可变模板参数和
std::tuple

#include <tuple>

template <typename... Args>
class Builder
{
public:
    explicit Builder(Args... args)
        : arg_tuple(std::forward<Args>(args)...)
    {}

    template <typename T>
    T make()
    {
        return std::make_from_tuple<T>(arg_tuple);
    }

    template <typename T>
    Builder<Args..., T> with(T t)
    {
        return std::make_from_tuple<Builder<Args..., T>>(std::tuple_cat(arg_tuple, std::make_tuple(std::move(t))));
    }

private:
    std::tuple<Args...> arg_tuple;
};

template <typename... Args>
Builder<Args...> make_builder(Args... args)
{
    return Builder<Args...>(std::forward<Args>(args)...);
}

您计划如何使用该生成器?是否要创建对象,例如,执行类似于
auto builder=make_builder().with().with()的操作;Foo f=builder.make(5,10.f)?假设
Foo
构造函数接受int和float arg。还是要将参数存储在生成器中?类似于
autobuilder=make_builder().with(5.with(10.f));Foo f=builder.make()
?@pschill-是,或多或少,除了它仅在对象类型上生成外(但是对象是模板-模板参数的类型传递给
make()
调用)。在内部,生成器跟踪的类型,如
T1
T2
不会影响生成的对象的类型,但在
make
函数中使用,例如,创建嵌入特定于
T1
T2
对象的行为的函数指针。您可以在
OneshotBuilder
中看到一个示例。这样做的目的是消除需要大量不同的
make()
开销,这些开销采用
TOUCH
样本
预热
等的不同组合,而是使用
with xxx()将这些开销嵌入make的类型中
调用以更新其中一种类型,并返回具有此类型但在其他方面未更改的新生成器。C++11是硬限制吗?或者你可以使用一些C++14的特性吗?我有一个很好的解决方案,但它需要可变模板参数。不幸的是,是的,这对我来说是一个很难的限制。这就是说,涉及C++14的解决方案对其他人来说肯定是有趣的@谢谢。这是非常通用的,可能并不完全适用于我的用例。在我的例子中,
make()
方法专门处理
Builder
对象的各种模板参数。例如,
T1
可能是一个非类型函数参数,
make()
方法可能会获取函数指针并包含到要生成的对象中。类似地,
T2
可以以不同的方式处理。所有这些都表明构建器不是泛型的,各种模板参数(类型和非类型)也不是同质的。然而,对于一般的齐次情形,这是一个很好的解决方案!
template<typename T1, typename T2>
struct Builder;

struct BuilderProxy
{
    int param1, param2;

    template<typename T1, typename T2>
    operator Builder<T1, T2>() const { return {param1, param2}; }
};

template <typename T1, typename T2>
struct Builder {
    int param1, param2;
    Builder(int param1, int param2) : param1{param1}, param2{param2} {}

    BuilderProxy copy() { return {param1, param2}; }

    template <typename T1_NEW>
    Builder<T1_NEW, T2   > withT1() { return copy(); }

    template <typename T2_NEW>
    Builder<T1   , T2_NEW> withT2() { return copy(); }
};

int main() {
    Builder<int, int> a(1, 2);
    Builder<double, double> b = a.withT1<double>().withT2<double>();
}
#include <tuple>

template <typename... Args>
class Builder
{
public:
    explicit Builder(Args... args)
        : arg_tuple(std::forward<Args>(args)...)
    {}

    template <typename T>
    T make()
    {
        return std::make_from_tuple<T>(arg_tuple);
    }

    template <typename T>
    Builder<Args..., T> with(T t)
    {
        return std::make_from_tuple<Builder<Args..., T>>(std::tuple_cat(arg_tuple, std::make_tuple(std::move(t))));
    }

private:
    std::tuple<Args...> arg_tuple;
};

template <typename... Args>
Builder<Args...> make_builder(Args... args)
{
    return Builder<Args...>(std::forward<Args>(args)...);
}
struct Foo
{
    Foo(int x, int y)
        : x(x), y(y)
    {}
    int x;
    int y;
};

struct Bar
{
    Bar(int x, int y, float a)
        : x(x), y(y), a(a)
    {}
    int x;
    int y;
    float a;
};

int main()
{
    auto b = make_builder().with(5).with(6);
    auto foo = b.make<Foo>();  // Returns Foo(5, 6).
    auto b2 = b.with(10.f);
    auto bar = b2.make<Bar>();  // Returns Bar(5, 6, 10.f).
}
namespace detail
{
    template <typename T, typename Tuple, std::size_t... I>
    constexpr T make_from_tuple_impl(Tuple&& t, std::index_sequence<I...>)
    {
        return T(std::get<I>(std::forward<Tuple>(t))...);
    }
}

template <typename T, typename Tuple>
constexpr T make_from_tuple(Tuple&& t)
{
    return detail::make_from_tuple_impl<T>(
        std::forward<Tuple>(t),
        std::make_index_sequence<std::tuple_size_v<std::remove_reference_t<Tuple>>>{});
}