递归定义元组

时间:2018-09-25 15:12:07

标签: c++ templates variadic-templates

我正在使用GCC8.2,我想定义一个这样的分层元组:

std::tuple<std::array<double,N>,
           std::array<double,N/2>,
           std::array<double,N/4>,
           ...,
           std::array<double,2> > v ;

然后我有一种算法,可以按照以下规范填充这些数组:

template <int N>
std::array<double,N> get_array()

如何编写通用算法来声明元组并在编译时为任何N填充它?

3 个答案:

答案 0 :(得分:3)

没有递归,您可能会做类似的事情:

template <std::size_t N>
std::array<double, N> get_array() { return {{}}; }

namespace detail
{

    constexpr std::size_t log2(std::size_t n)
    {
        std::size_t res = 0;
        while (n != 0) {
            n /= 2;
            ++res;
        }
        return res;
    }

    template <std::size_t N, std::size_t ...Is>
    auto make_array_tuple_impl(std::index_sequence<Is...>)
    {
        return make_tuple(get_array<(N >> Is)>()...);
    }

}

template <std::size_t N>
auto make_array_tuple()
{
    return detail::make_array_tuple_impl<N>(std::make_index_sequence<detail::log2(N) - 1>());
}

Demo

答案 1 :(得分:2)

这有点涉及,也许有一个更简单的解决方案。

AppiumDriver<AndroidElement> driver;
    [TestInitialize]
    public void OpenApp()
    {
        DesiredCapabilities cap = new DesiredCapabilities();
        cap.SetCapability("noReset", "true");
        cap.SetCapability("device", "Android");
        cap.SetCapability("deviceName", "Galaxy S8");
        cap.SetCapability("platformVersion", "8.0.0");
        cap.SetCapability("platformName", "Android");
        cap.SetCapability("automationName", "UiAutomator2");
        cap.SetCapability("appPackage", "com.goldex");
        cap.SetCapability("appActivity", "com.goldex.view.activity.MainActivity");
        driver = new AndroidDriver<AndroidElement>(new Uri("http://127.0.0.1:4723/wd/hub"), cap);
    }
    [TestMethod]
    public void ViewBulbasaur()
    {
        // Arrange
        driver.FindElementByXPath("//android.widget.TextView[contains(@text, 'Bulbasaur')]").Click();
        // Assert
        var objText = driver.FindElementByXPath("//android.widget.TextView[contains(@text, 'Bulbasaur #001')]").Text;
        Assert.AreEqual("Bulbasaur #001", objText);
    }
    [TestMethod]
    public void ViewIvysaur()
    {
        //Arrange
        driver.FindElementByXPath("//android.widget.TextView[contains(@text, 'Ivysaur')]").Click();
        // Assert
        var objText = driver.FindElementByXPath("//android.widget.TextView[contains(@text, 'Ivysaur #002')]").Text;
        Assert.AreEqual("Ivysaur #002", objText);
    }
    [TestMethod]
    public void ViewVenusaur()
    {
        //Arrange
        driver.FindElementByXPath("//android.widget.TextView[contains(@text, 'Venusaur')]").Click();
        // Assert
        var objText = driver.FindElementByXPath("//android.widget.TextView[contains(@text, 'Venusaur #003')]").Text;
        Assert.AreEqual("Venusaur #003", objText);
    }
    [TestMethod]
    public void ViewMegaVenusaur()
    {
        //Arrange
        driver.FindElementByXPath("//android.widget.TextView[contains(@text, 'Mega Venusaur')]").Click();
        // Assert
        var objText = driver.FindElementByXPath("//android.widget.TextView[contains(@text, 'Mega Venusaur #003')]").Text;
        Assert.AreEqual("Mega Venusaur #003", objText);
    }
    [TestMethod]
    public void ViewCharmander()
    {
        //Arrange
        driver.FindElementByXPath("//android.widget.TextView[contains(@text, 'Charmander')]").Click();
        // Assert
        var objText = driver.FindElementByXPath("//android.widget.TextView[contains(@text, 'Charmander #004')]").Text;
        Assert.AreEqual("Charmander #004", objText);
    }
    [TestCleanup]
    public void CloseApp()
    {
        driver.CloseApp();
    }

See it live on Coliru

答案 2 :(得分:1)

您确定

中的序列吗
std::tuple<std::array<double,N>,
           std::array<double,N/2>,
           std::array<double,N/4>,
           ...,
           std::array<double,2> > v ;

2结尾吗?

假设您想以21结尾,我想您可以使用以下自定义类型特征获取所需的索引序列

template <std::size_t N, std::size_t ... Is>
struct divSequence : public divSequence<(N>>1u), Is..., (N>>1u)>
 { };

template <std::size_t ... Is>
struct divSequence<2u, Is...> : public std::index_sequence<Is...>
 { };

template <std::size_t ... Is>
struct divSequence<1u, Is...> : public std::index_sequence<Is...>
 { };

因此,您仅需要以下make函数(带有帮助程序)

template <std::size_t ... Is>
std::tuple<std::array<double, Is>...>
   getDivTupleHelper (std::index_sequence<Is...> const &)
 { return { get_array<Is>()... }; }

template <std::size_t N>
auto getDivTuple ()
 { return getDivTupleHelper(divSequence<N>{}); }

以下是完整的C ++ 14示例

#include <array>
#include <tuple>
#include <utility>

template <std::size_t N>
std::array<double,N> get_array ()
 { return {{ }}; }

template <std::size_t N, std::size_t ... Is>
struct divSequence : public divSequence<(N>>1u), Is..., (N>>1u)>
 { };

template <std::size_t ... Is>
struct divSequence<2u, Is...> : public std::index_sequence<Is...>
 { };

template <std::size_t ... Is>
struct divSequence<1u, Is...> : public std::index_sequence<Is...>
 { };

template <std::size_t ... Is>
std::tuple<std::array<double, Is>...>
   getDivTupleHelper (std::index_sequence<Is...> const &)
 { return { get_array<Is>()... }; }

template <std::size_t N>
auto getDivTuple ()
 { return getDivTupleHelper(divSequence<N>{}); }


int main ()
 {
   using t0 = decltype( getDivTuple<15u>() );
   using t1 = std::tuple<std::array<double, 7u>,
                         std::array<double, 3u>,
                         std::array<double, 1u>>;
   using t2 = decltype( getDivTuple<16u>() );
   using t3 = std::tuple<std::array<double, 8u>,
                         std::array<double, 4u>,
                         std::array<double, 2u>>;

   static_assert( std::is_same<t0, t1>::value, "!");
   static_assert( std::is_same<t2, t3>::value, "!");
 }

如果您需要C ++ 11解决方案...那么...代替std::index_sequence,可以使用自定义平凡替代品

template <std::size_t ...>
struct myIndexSequence
 { }

,您需要重写getDivTuple()以使用decltype()显式地返回类型;像

template <std::size_t N>
decltype(getDivTupleHelper(divSequence<N>{})) getDivTuple ()
 { return getDivTupleHelper(divSequence<N>{}); }