类型C++支持的表达式语法是什么?

abi*_*bir 16 c++ templates c++11

我正在使用一个带有一组整数的模板化类.代码就像,

template<unsigned... Idx>
struct work{ ... };
Run Code Online (Sandbox Code Playgroud)

然后我意识到,用户可能需要提供一组整数或一系列整数.所以,我改变了语法,以支持实例化,如,

work<indexes<1,3,2,4> > //instead of work<1,3,2,4>
work<span<1,4> > //same as work<1,2,3,4> 
Run Code Online (Sandbox Code Playgroud)

同时,在C++,我们有大量的运营商,并且可以被用于配制异国表达式模板(比方说boost::xpressive,boost::lambda,boost::spirit等等),用于类型操纵可能性要少得多.

在Sean Parent的一个boostcon主题演讲中,他指出一个仍然不能写pair<int>的表示a pair of integers.在我的persinal库中,我做了一个语法,就像tuple<int[3]>表示一个3个整数的元组,而不是在类型参数中写一个带有3个int的元组,注意到我没有在任何地方写一个原始数组作为元组参数!(注意:std::array<int,3>与上面不一样,因为std :: array不能存储引用,tuple可以说std::tuple<int&,int&,int&>,可以)

所以,我想知道我能写的不同类型的"类型表达式"是什么?

到目前为止,我可以想到对象类型,函数类型,引用类型,有/无cv修饰符,指针等

    template<class T>
    struct tpl;

    using t1 = tpl<int>;//simple type
    //function (can have function pointer/reference also) 
    // e.g. void(*)(int,float) or void(&)(int,float)
    using t2 = tpl<void(int,float)>;
    //array can have pointer / reference also
    //e.g. int(&)[4] or int (*)[4]
    using t3 = tpl<int[4]>;
    using t4 = tpl<int[]>;
    using t5 = tpl<int const>;//with cv modifiers
    using t6 = tpl<int*>;//with pointer
    using t7 = tpl<int&>;//with reference (& or &&)
    using t8 = tpl<tpl<int> >; //template itself
    using t9 = tpl<void(...)>; //variadic functions
    using t10 = tpl<R C::*>; //pointer to member
Run Code Online (Sandbox Code Playgroud)

但我相信,还有更多是可能的.

注意:这个问题纯粹是理论上的,我只是想知道我可以在<>中作为类型参数编写的各种语法,而不是关于它的可读性/道德方面,甚至我如何实现我拥有的一些例子给予,像工人阶级一样.

wil*_*llj 12

可以使用声明符语法构造复合类型 - 在中找到[dcl.decl].

这种语法的基础是六个基本结构,其中任何T都可以被列表中的任何其他结构替代.[在下文中,(T)表示零个或多个类型的列表(可以以'...'结尾),并<T>表示一个或多个类型的列表.

T // T
T* // pointer to T
T& // reference to T
T[n] // array of size 'n' of T
T C::* // pointer to C::member of type T
T (T) // function taking '(T)' and returning T
Run Code Online (Sandbox Code Playgroud)

编辑:类模板专业化的类型可以替代任何T:

C<T> // specialization of class template C with arguments '<T>'
Run Code Online (Sandbox Code Playgroud)

以上组合产生具有特殊意义的构造:

T (*)(T) // pointer to function taking '(T)' and returning T
T (C::*)(T) // pointer to C::member-function taking '(T)' and returning T
Run Code Online (Sandbox Code Playgroud)

另外,一些构造可能是cv限定的:

const T // const T
T* const // const pointer to T
T C::* const // const pointer to C::member of type T
Run Code Online (Sandbox Code Playgroud)

并非所有组合都会产生有效类型.根据[basic.compound],只能使用以下组合:

化合物类型可以通过以下方式构建:

  • 给定类型的对象数组
  • 函数,具有给定类型的参数并返回void或给定类型的引用或对象
  • 指向void或指定类型的对象或函数(包括类的静态成员)的指针
  • 对给定类型的对象或函数的引用
  • 指向非静态类成员的指针,用于标识给定类的对象内给定类型的成员

提到了其他限制:

[dcl.ptr] 没有指向引用的指针

[dcl.ref] 不应引用引用,不引用引用数组,也不引用引用指针

[dcl.mptr] 指向成员的指针不应指向......具有引用类型的成员,或"cv void".

[dcl.fct]参数列表(void)等效于空参数列表.除了这种特殊情况,void不应该是参数类型....如果参数的类型包括"指向T的未知界限的数组的指针"或"对T的未知界限的数组的引用"的形式,则该程序是错误的.函数不应具有类型数组或函数的返回类型.

某些可能的构造不能用作模板参数.当您显式指定一组模板参数时,编译器必须检查template-arguments是否可以替换模板参数,而不会导致"无效类型".根据[temp.deduct]\2,以下构造构成无效类型:

由于以下原因,类型扣除可能会失败:

  • 尝试创建具有void,函数类型或引用类型的元素类型的数组,或尝试创建大小为零或负的数组.

    template <class T> int f(T[5]);
    int I = f<int>(0);
    int j = f<void>(0); // invalid array
    
    Run Code Online (Sandbox Code Playgroud)
  • 试图在限定名称中使用不是类类型的类型.

    template <class T> int f(typename T::B*);
    int i = f<int>(0);
    
    Run Code Online (Sandbox Code Playgroud)
  • 尝试在限定名称的限定符部分中使用类型,该类型在该类型不包含指定成员时命名类型,或者指定的成员不是需要类型的类型.

    template <class T> int f(typename T::B*);
    struct A {};
    struct C { int B; };
    int i = f<A>(0);
    int j = f<C>(0);
    
    Run Code Online (Sandbox Code Playgroud)
  • 试图创建指向引用类型的指针.

  • 尝试创建对引用类型的引用或对void的引用.

  • 当T不是类类型时,尝试创建"指向T成员的指针".

    template <class T> int f(int T::*);
    int i = f<int>(0);
    
    Run Code Online (Sandbox Code Playgroud)
  • 尝试在模板参数表达式或函数声明中使用的表达式中执行无效转换.

    template <class T, T*> int f(int);
    int i2 = f<int,1>(0); // can’t conv 1 to int*
    
    Run Code Online (Sandbox Code Playgroud)
  • 试图创建一个函数类型,其中参数的类型为void.

  • 试图创建一个cv限定的函数类型.

编辑:这是基于C++ 03,但也适用于C++ 11(添加右值引用类型)


seh*_*ehe 6

我不完全确定你在问什么.我认为你给的样本很有趣,并且有点玩.

我想出了让一个实现span<a,b>是一个模板别名indexes<a, ..., b>,使用类型推演的绝招constexpr功能:

template <int a, int b> using span = decltype(expand_span<a,b>());
Run Code Online (Sandbox Code Playgroud)

现在你可以吃蛋糕了:

////////////////////////////////////////////////////////////////
// using indirect template arguments
template<typename> struct indirect_work { };

void test_indirect()
{
    indirect_work<indexes<1,2,3,4>> x;
    indirect_work<span<1,4>>        y;

    x = y; // x and y are of identical types
    static_assert(std::is_same<indexes<1,2,3,4>, span<1,4>>::value, "fact check");
}
Run Code Online (Sandbox Code Playgroud)

但是,也许更有趣的是,您仍然可以让主work模板采用原始<int...>模板参数列表:

////////////////////////////////////////////////////////////////
// using direct template arguments
template<int...> struct direct_work { };

// deduction alias:
template<int... direct> constexpr direct_work<direct...> deduction_helper(indexes<direct...>);
template <typename Idx> using deduce = decltype(deduction_helper(Idx{}));

void test_direct()
{
    direct_work<1,2,3,4> x;
    deduce<indexes<1,2,3,4>> y;
    deduce<span<1,4>> z;

    static_assert(std::is_same<decltype(x), decltype(y)>::value, "fact check");
    static_assert(std::is_same<decltype(x), decltype(z)>::value, "fact check");
}
Run Code Online (Sandbox Code Playgroud)

在这里查看完整的工作演示:gcc on ideone.我在本地用clang编译它.


完整代码

expand_span在这里重复的代码链接应该死了:

#include <type_traits>

template <int...> struct indexes {};

namespace {
    template<int a, int... other>
        constexpr indexes<a, other...> combine(indexes<other...> deduce);

    template<int a, int b, typename Enable = void> struct expand_span_; // primary

    template<int a, int b>
    struct expand_span_<a, b, typename std::enable_if< (a==b), void >::type> {
        static constexpr indexes<a> dispatch();
    };

    template<int a, int b>
    struct expand_span_<a, b, typename std::enable_if< (a<b), void >::type> {
        static constexpr decltype(combine<a>(expand_span_<a+1, b>::dispatch())) 
            dispatch();
    };

    template<int a, int b>
    constexpr auto expand_span() -> decltype(expand_span_<a,b>::dispatch());
}

template <int a, int b> using span = decltype(expand_span<a,b>());

////////////////////////////////////////////////////////////////
// using indirect template arguments
template<typename> struct indirect_work { };

void test_indirect()
{
    indirect_work<indexes<1,2,3,4>> x;
    indirect_work<span<1,4>>        y;

    x = y; // x and y are of identical types
    static_assert(std::is_same<indexes<1,2,3,4>, span<1,4>>::value, "fact check");
}

////////////////////////////////////////////////////////////////
// using direct template arguments
template<int...> struct direct_work { };

// deduction alias:
template<int... direct> constexpr direct_work<direct...> deduction_helper(indexes<direct...>);
template <typename Idx> using deduce = decltype(deduction_helper(Idx{}));

void test_direct()
{
    direct_work<1,2,3,4> x;
    deduce<indexes<1,2,3,4>> y;
    deduce<span<1,4>> z;

    static_assert(std::is_same<decltype(x), decltype(y)>::value, "fact check");
    static_assert(std::is_same<decltype(x), decltype(z)>::value, "fact check");
}

int main()
{
    test_indirect();
    test_direct();
}
Run Code Online (Sandbox Code Playgroud)