Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/templates/2.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++_Templates_C++11 - Fatal编程技术网

C++ 模板:如何使用模板变量控制构造函数参数的数量。

C++ 模板:如何使用模板变量控制构造函数参数的数量。,c++,templates,c++11,C++,Templates,C++11,我试图用这种方式创建一个简单的向量类(数学): template <int D, typename T = float> class Vector { T m[D]; // ... }; 仅当D为特定数字时,如何添加函数?我希望添加GetX()如果D为>=1,GetY()如果D为>=2和GetZ()如果D为>=3,但以下代码应生成编译时错误: Vector<2> v(1.0f, -6.3f); cout << v.GetZ() << en

我试图用这种方式创建一个简单的向量类(数学):

template <int D, typename T = float>
class Vector
{
  T m[D];
  // ...
};
仅当
D
为特定数字时,如何添加函数?我希望添加
GetX()
如果
D
为>=1,
GetY()
如果
D
为>=2和
GetZ()
如果
D
为>=3,但以下代码应生成编译时错误:

Vector<2> v(1.0f, -6.3f);
cout << v.GetZ() << endl;
向量v(1.0f,-6.3f);

cout这有点离题,但可能是工作量最少的:使用
元组。然后,您可以免费获得所有访问器函数

剩下唯一要做的就是创建一个元组工厂:

template <typename T, unsigned int D> struct tuple_maker
{
  typedef typename tcat<T, tuple_maker<T, D - 1>::type>::type type;
}
template <typename T> struct tuple_maker<T, 1>
{
  typedef std::tuple<T> type;
}
用法:

tuple_maker<float, 3>::type myVec3D;
tuple\u maker::键入myVec3D;
使用模板别名,我们可以做得更好:

template <typename T, unsigned int D>
using MyVector = typename tuple_maker<T, D>::type;

MyVector<double, 4> myVec4D;
模板
使用MyVector=typename tuple\u maker::type;
myVec4D;

如何将构造函数声明为接受T类型的D参数

你不能那样做。您可以对每个支持的维度进行专门化,并为每个维度提供适当的构造函数。或者,您可以定义一个构造函数,该构造函数接受多个默认值参数,并忽略未使用的参数。或者,如果参数的数量大于
D
,则可以定义多个构造函数,从1到某个上限,以及
static\u assert

如果D是一个特定的数字,如何添加一个函数

这是通过专业化实现的。您必须将所有公共功能移动到某个向量基模板并从中继承,然后对维度进行部分专门化以添加这些功能

如果D<1,如何生成编译时错误


或者您可以为基本模板定义所有这些函数,如果
D
不足以使用该函数,则可以使用
static\u assert
。现在您已经丢失了显式实例化。您还可以向这些函数添加一个伪模板参数,这样您就可以使用
enable\u if
和SFINAE来丢弃函数。

所以我提供了一个人们喜欢的愚蠢答案。但这比那容易多了:)

模板
第五类{
公众:
模板
v(Args…Args):a{T(Args)…}{
静态断言(sizeof…(Args)==D,“参数数目错误”);
}
私人:
Tα[D];
};

您可以使用可变模板和SFINAE获得具有正确数量参数的构造函数

构造函数没有返回值,因此我们需要在其中一个参数上使用SFINAE。要使用可变模板,我们需要在末尾有参数包

这意味着我们需要在第一个参数上使用SFINAE

这意味着第一个参数后的参数包需要比尺寸少一个参数

有了这个,我们可以写:

template <int D, typename T>
class v {
public:
    template <typename... Tail>
    v(typename std::enable_if<sizeof...(Tail)+1 == D, T>::type head, Tail... tail)
    : a{ head, T(tail)... } {}

private:
    T a[D];
};
模板
第五类{
公众:
模板
v(typename std::enable_if::type head,Tail…Tail)
:a{head,T(tail)…}{}
私人:
Tα[D];
};
现在:

v<4, int> a(1,2,3,4); // ok!
v<4, int> b(1,2,3);   // error! no such constructor
va(1,2,3,4);//好啊
vb(1,2,3);//错误!没有这样的构造函数

这应该可以完成以下工作:

template<int N, typename T>
class Array
{
private:
    T Data[N];

public:
    template<int i>
    void Init() { }
    template<int i, typename... Args>
    void Init(T Arg0, Args... Rest)
    {
        Data[i] = Arg0;
        Init<i + 1>(Rest...);
    }
    template<typename... Args>
    Array(T Arg0, Args... Rest)
    {
        static_assert(sizeof...(Args) + 1 == 5, "Wrong number of arguments");
        Data[0] = Arg0;
        Init<1>(Rest...);
    }
};

int main (int argc, const char * argv[])
{
    Array<5, int> arr(1, 2, 3, 4, 5);
    return 0;
}
模板
类数组
{
私人:
T数据[N];
公众:
模板
void Init(){}
模板
void Init(T Arg0,Args…Rest)
{
数据[i]=Arg0;
Init(Rest…);
}
模板
数组(T Arg0,Args…Rest)
{
静态断言(sizeof…(Args)+1==5,“参数数目错误”);
数据[0]=Arg0;
Init(Rest…);
}
};
int main(int argc,const char*argv[]
{
阵列arr(1,2,3,4,5);
返回0;
}

我没有访问C++11编译器的权限,但这样的东西可能行得通吗

#include <array>
#include <type_traits>

template <int D, typename T>
class Vector
{
    static_assert(D > 0, "Dimension must be greater than 0");
    std::array<T,D> m;
public:
    template<typename... Args>
    Vector(Args&&... args) : m{T(args)...}
    {
         static_assert(sizeof...(Args) == D, "Invalid number of constructor arguments.");
    }

    T GetX() const { return m[0]; }
    T GetY() const { return m[1]; }
    T GetZ() const { return m[2]; }
};

template <typename T>
class Vector<1, T>
{
    std::array<T,1> m;
public:
    Vector(const T& t0) : m{t0}
    {
    }

    T GetX() const { return m[0]; }
};

template <typename T>
class Vector<2, T>
{
    std::array<T,2> m;
public:
    Vector(const T& t0, const T& t1) : m{t0, t1}
    {
    }

    T GetX() const { return m[0]; }
    T GetY() const { return m[1]; }
};
#包括
#包括
模板
类向量
{
静态_断言(D>0,“维度必须大于0”);
std::数组m;
公众:
模板
向量(Args&…Args):m{T(Args)…}
{
静态_断言(sizeof…(Args)==D,“构造函数参数的数目无效”);
}
T GetX()常量{返回m[0];}
T GetY()常量{return m[1];}
T GetZ()常量{return m[2];}
};
模板
类向量
{
std::数组m;
公众:
向量(常数T&t0):m{t0}
{
}
T GetX()常量{返回m[0];}
};
模板
类向量
{
std::数组m;
公众:
向量(常数T&t0,常数T&t1):m{t0,t1}
{
}
T GetX()常量{返回m[0];}
T GetY()常量{return m[1];}
};

您可以使用varadic模板does
Vector
有意义吗?:)我会使用
std::size\u t
而不是
int
@GMan
Vector
也没有意义。不管怎样,
size\t
更好。@LBg:你可以把它专门化,让它有意义,但那样就没有意义了如果你从元组继承,你可以直接继承它的构造函数(如果编译器支持的话)!好吧,那很有效。但我仍然对如何“用手”做这件事感到好奇。而且,这样,我就不能添加额外的方法。“手动”本质上与实现
tuple
的方法相同。。。或者,您可以选择
array
(基本上就像您已经做的那样),并添加一个带有大括号初始值设定项列表的构造函数。你不会得到像那样的自由移动或就地构造,但对于浮点类型来说,这也许是可以的。(注意,
std::array
std::tuple
是惊人的相似类型;你可以将
std::array
几乎完全像
std::tuple
一样对待)你不认为写
tuple*evil=newvector的人
值得他从中得到什么?@R.MartinhoFernandes:或者继承加上转发构造函数调用…“我如何声明构造函数函数接受T类型的D个参数?你不能这样做”那不是真的。。。他可以用瓦拉迪奇templates@Dani:您如何声明它只接受
D
D
参数?@K-ballo:原始注释已被删除。这是关于如何制作一个构造器
v<4, int> a(1,2,3,4); // ok!
v<4, int> b(1,2,3);   // error! no such constructor
template<int N, typename T>
class Array
{
private:
    T Data[N];

public:
    template<int i>
    void Init() { }
    template<int i, typename... Args>
    void Init(T Arg0, Args... Rest)
    {
        Data[i] = Arg0;
        Init<i + 1>(Rest...);
    }
    template<typename... Args>
    Array(T Arg0, Args... Rest)
    {
        static_assert(sizeof...(Args) + 1 == 5, "Wrong number of arguments");
        Data[0] = Arg0;
        Init<1>(Rest...);
    }
};

int main (int argc, const char * argv[])
{
    Array<5, int> arr(1, 2, 3, 4, 5);
    return 0;
}
#include <array>
#include <type_traits>

template <int D, typename T>
class Vector
{
    static_assert(D > 0, "Dimension must be greater than 0");
    std::array<T,D> m;
public:
    template<typename... Args>
    Vector(Args&&... args) : m{T(args)...}
    {
         static_assert(sizeof...(Args) == D, "Invalid number of constructor arguments.");
    }

    T GetX() const { return m[0]; }
    T GetY() const { return m[1]; }
    T GetZ() const { return m[2]; }
};

template <typename T>
class Vector<1, T>
{
    std::array<T,1> m;
public:
    Vector(const T& t0) : m{t0}
    {
    }

    T GetX() const { return m[0]; }
};

template <typename T>
class Vector<2, T>
{
    std::array<T,2> m;
public:
    Vector(const T& t0, const T& t1) : m{t0, t1}
    {
    }

    T GetX() const { return m[0]; }
    T GetY() const { return m[1]; }
};