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 番目のバージョンで使用される型を 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もリテラル型であるため、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 に答える