3

考虑以下示例(我今天发布了几个不同的问题):

#include <iostream>
#include <vector>
#include <array>
#include <type_traits>

// Version A
template<typename T>
constexpr unsigned int f(const T&)
{
    return 1;
}

// Version B
template<typename... T1, template<typename...> class T>
constexpr unsigned int f(const T<T1...>&)
{
    return 2;
}

// Version C
template<typename T1, template<typename, unsigned int...> class T, unsigned int... N>
constexpr unsigned int f(const T<T1, N...>&)
{
    return 3;
}

// Main
int main(int argc, char* argv[])
{
    std::integral_constant<int, f(double())> a;
    std::integral_constant<int, f(std::vector<double>())> b;
    std::integral_constant<int, f(std::array<double, 3>())> c;
    std::cout<<a<<b<<c<<std::endl; // The goal is to return 123
    return 0;
}

此代码无法编译并返回以下编译错误:

temporary of non-literal type 'std::vector<double>' in a constant expression

如何修改此代码以编译它?

注意:目标是将函数的第一个版本采用的类型转换为 1,将函数的第二个版本采用的类型转换为 2,等等...

4

4 回答 4

2

您需要部分专业化,这在函数上是不可能的,将它们包装在结构/类中即可完成工作:

#include <iostream>
#include <vector>
#include <array>
#include <type_traits>

// Version A                                                                                                                                                   
template<typename T>
struct f
{
  constexpr static unsigned int execute()                                                                                                                      
  {                                                                                                                                                            
    return 1;                                                                                                                                                  
  }
};

// Version B                                                                                                                                                   
template<template <typename ... > class Tpl, typename ... TplArgs>
struct f< Tpl<TplArgs...> >
{
  constexpr static unsigned int execute()                                                                                                                      
  {                                                                                                                                                            
    return 2;                                                                                                                                                  
  }
};

// Version C                                                                                                                                                   
template<template<typename, std::size_t...> class Tpl, typename FirstArg, std::size_t... N>
struct f< Tpl<FirstArg, N...> >
{
  constexpr static unsigned int execute()                                                                                                                      
  {                                                                                                                                                            
    return 3;                                                                                                                                                  
  }
};

// Main                                                                                                                                                        
int main(int argc, char* argv[])                                                                                                                               
{                                                                                                                                                              
  std::integral_constant<int, f<double>::execute()> a;                                                                                                         
  std::integral_constant<int, f<std::vector<double>>::execute()> b;                                                                                            
  std::integral_constant<int, f<std::array<double, 3>>::execute()> c;                                                                                          

  std::cout << a << ' ' << b << ' ' << c << std::endl;

  return 0;
}                                                                                                        
于 2012-12-18T11:34:24.200 回答
1

定义常量时不能使用临时向量:

int main(int argc, char* argv[])
{
    std::integral_constant<int, f(double())> a;
    std::vector<double> vec;
    std::integral_constant<int, f(vec)> b;
    std::integral_constant<int, f(std::array<double, 3>())> c;

    std::cout << a << b << c;
    return 0;
}

问题是编译器可能会省略vector创建,如果向量的唯一目的是传递给常量表达式函数,但实际上它不能,因为向量不是文字类型。

std::array只是 c 数组之上的一个事物包装器,它具有微不足道的构造函数和析构函数。由于 double 也是文字类型,所以双精度数组变为文字。

但是请注意,如果您定义

struct A
{
    A(){std::cout << "I'm so complicated A!\n"; }
}

您将无法使用构造:

int main(int argc, char* argv[])
{
    std::integral_constant<int, f(A())> a;
    std::integral_constant<int, f(std::array<A, 3>())> c;

    std::cout << a << b << c;
    return 0;
}

要么,而

int main(int argc, char* argv[])
{
    A a_v;
    std::integral_constant<int, f(a_v)> a;

    std::array<A, 3> c_v
    std::integral_constant<int, f(c_v)> c;

    std::cout << a << b << c;
    return 0;
}

仍然是可能的。

于 2012-12-17T20:22:36.270 回答
0

您的问题是,我们能负担多少修改此代码的费用?例如,以下编译,但它是你想要做的吗?

#include <iostream>
#include <vector>
#include <array>
#include <type_traits>

// Version A
template<typename T>
constexpr unsigned int f()
{
    return 1;
}

// Version B
template<typename... T1, template<typename...> class T>
constexpr unsigned int f()
{
    return 2;
}

// Version C
template<typename T1 = double, template<typename, unsigned int...> class T, unsigned int... N>
constexpr unsigned int f()
{
    return 3;
}

// Main
int main(int argc, char* argv[])
{
    std::integral_constant<int, f<double>()> a;
    std::integral_constant<int, f<std::vector<double>>()> b;
    std::integral_constant<int, f<std::array<double, 3>>()> c;
    return 0;
}
于 2012-12-17T20:29:54.660 回答
0

我通过使用指针而不是引用找到了解决方案:

// Version A
template<typename T>
constexpr unsigned int f(const T*)
{
    return 1;
}

// Version B
template<typename... T1, template<typename...> class T>
constexpr unsigned int f(const T<T1...>*)
{
    return 2;
}

// Version C
template<typename T1, template<typename, unsigned int...> class T, unsigned int... N>
constexpr unsigned int f(const T<T1, N...>*)
{
    return 3;
}

// Main
int main(int argc, char* argv[])
{
    std::vector<double> tmp;
    std::integral_constant<int, f(static_cast<double*>(nullptr))> a;
    std::integral_constant<int, f(static_cast<decltype(tmp)*>(nullptr))> b;
    std::integral_constant<int, f(static_cast<std::array<double, 3>*>(nullptr)) > c;
    std::cout<<a<<b<<c<<std::endl;
    return 0;
}

也许这不是最优雅的方式,但它确实有效。如果有人有一个优雅的等价物,我很感兴趣。

于 2012-12-17T21:05:12.477 回答