C++ 有没有办法在编译时检查std::initializer\u列表中的参数数?

C++ 有没有办法在编译时检查std::initializer\u列表中的参数数?,c++,templates,c++11,initializer-list,compile-time,C++,Templates,C++11,Initializer List,Compile Time,我试图创建一个函数,该函数将接受给定类型的多个参数,但参数的类型和数量都应通过模板指定 我发现在这种情况下,使用C++11的初始值设定项_list可能是一种很好的技术,但是否可以在编译时检查其大小?有没有其他技术可以解决这个问题 #include <initializer_list> // Here I want to define type and number of components for each point template <typename T, int

我试图创建一个函数,该函数将接受给定类型的多个参数,但参数的类型和数量都应通过模板指定

我发现在这种情况下,使用C++11的初始值设定项_list可能是一种很好的技术,但是否可以在编译时检查其大小?有没有其他技术可以解决这个问题

#include <initializer_list>

// Here I want to define type and number of components for each point

template <typename T, int DIM>
class Geometry
{
public:
    void addPoint(std::initializer_list<T> coords)
    {
        assert(coords.size() == DIM); // Working good, but not compile-time

        // Next line does not compile because size() is not known at compile-time
        static_assert(coords.size() == DIM, "Wrong number of components"); 
    }
};
#包括
//这里我想为每个点定义组件的类型和数量
模板
类几何
{
公众:
无效添加点(标准::初始值设定项\u列表坐标)
{
assert(coords.size()==DIM);//工作正常,但不是编译时
//下一行不编译,因为编译时不知道size()
静态断言(coords.size()=DIM,“组件数量错误”);
}
};

您不能静态地断言运行时数量。而
初始值设定项列表中的值的数量是由函数的调用方在运行时决定的

即使使函数
constexpr
也不起作用,因为函数的求值不需要在编译时进行

你应该改为使用可变模板。

多亏了,我开始关注可变模板。问题不仅在于检查参数的数量,还在于检查它们的类型是否可转换为基类型。以下是我基于和主题的解决方案。它按照GCC 4.9中的预期工作

template<class T, class...>
struct are_convertible : std::true_type
{};

template<class T, class U, class... TT>
struct are_convertible<T, U, TT...>
    : std::integral_constant<bool, std::is_convertible<T,U>{} && are_convertible<T, TT...>{}>
{};

template <typename T, int DIM>
class Geometry
{
public:
    template<typename... Args>
    void addPoint(Args... coords)
    {
        static_assert(sizeof...(coords) == DIM, "Number of components does not match template");
        static_assert(are_convertible<T, Args...>{}, "All arguments' types must be convertible to the template type"); 
    }
};
模板
结构是可转换的:std::true\u类型
{};
模板
结构是可转换的
:std::积分常数
{};
模板
类几何
{
公众:
模板
无效添加点(Args…coords)
{
静态断言(sizeof…(coords)=DIM,“组件数量与模板不匹配”);
static_assert(are_convertable{},“所有参数的类型必须可转换为模板类型”);
}
};

添加带有DIM数据成员的POD类点最不适合您的目的。然后隐式构造函数调用将确保一切正常

不知何故,这个问题不断浮出水面。如果您想使用初始值设定项列表语法调用
addPoint
,解决方案是使用
template void addPoint(const T(&coords)[N])
。然后,您可以在函数体中
静态断言(N==DIM,”)
。然而,这是最近在标准草案中指定的(一年前),所以Clang还不支持它(看起来在3.8.0中会支持)。它在GCC(合理的最新版本)和Visual C++ 2015中工作。@波格丹:好的解决方案!但是,据我所见,它有一个缺点:当我尝试传递一个整数而不是像
geo.addPoint({1.0,2})这样的基类型double时我得到以下错误:
不匹配的类型“double”和“int”
。变量模板不仅允许我检查严格的类型相等性,还允许我执行类型转换。看起来像GCC中的一个错误-它试图在不应该的时候推断元素类型。感谢您的澄清!以前从未处理过可变模板,但您的anwser激励我探索这个主题。把我的解决方案贴在下面。我不确定它是否很优雅,但它解决了问题。我不确定我理解你的意思。你能举个例子吗?
std::is_convertible
检查
T
是否可转换为
U
,而不是相反。还要记住,初始值设定项列表禁止缩小转换范围,而此解决方案不允许。