微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

如何将void模板类型用于编译时条件代码和static_assert?

如何解决如何将void模板类型用于编译时条件代码和static_assert?

我有遍历函数,该函数为每个元素调用回调,并希望在编译时使用非认参数实现其逻辑扩展,如下所示:

#include <type_traits>
#include <iostream>
using namespace std;

template<
    typename Odds = void,typename Evens = void,typename Skip = void
>
void iterate(
    const auto & on_element,const auto & skip 
) {
    for ( int i = 0; i < 6; ++ i ) {
        if constexpr ( ! is_same_v< Skip,void > ) {
            if ( skip.find( i ) != skip.end() )
                continue;
        }

        if ( i % 2 == 1 ) {
            if constexpr ( is_same_v< Odds,void > )
                on_element( i );
        }
        else {
            if constexpr ( is_same_v< Evens,void > )
                on_element( i );
        }

        static_assert(
            is_same_v< Odds,void > || is_same_v< Evens,void >,"Either odds or evens are required to get traversed"
        );
    }
}

int main() {
    const auto & on_element = []( const int & i ) {
        cout << "    " << i << endl;
    };

    cout << "Whole range:" << endl;
    iterate( on_element );

    cout << "Should skip specified elements:" << endl;
    iterate( on_element,{ 1,2,3 } );

    cout << "Should traverse only evens:" << endl;
    iterate< bool >( on_element );

    cout << "Should traverse only odds:" << endl;
    iterate< void,bool >( on_element );

    //should NOT compile if uncomment:
    //iterate< bool,bool >( on_element );
}

但是它不能与g++ -std=gnu++2a -fconcepts main.cpp -o main一起编译:

main.cpp: In function ‘int main()’:
main.cpp:42:25: error: no matching function for call to ‘iterate(const main()::<lambda(const int&)>&)’
   42 |     iterate( on_element );
      |                         ^
main.cpp:10:6: note: candidate: ‘template<class Odds,class Evens,class Skip,class auto:11,class auto:12> void iterate(const auto:11&,const auto:12&)’
   10 | void iterate(
      |      ^~~~~~~
main.cpp:10:6: note:   template argument deduction/substitution Failed:
main.cpp:42:25: note:   candidate expects 2 arguments,1 provided
   42 |     iterate( on_element );
      |                         ^
main.cpp:45:38: error: no matching function for call to ‘iterate(const main()::<lambda(const int&)>&,<brace-enclosed initializer list>)’
   45 |     iterate( on_element,3 } );
      |                                      ^
main.cpp:10:6: note: candidate: ‘template<class Odds,const auto:12&)’
   10 | void iterate(
      |      ^~~~~~~
main.cpp:10:6: note:   template argument deduction/substitution Failed:
main.cpp:45:38: note:   Couldn’t deduce template parameter ‘auto:12’
   45 |     iterate( on_element,3 } );
      |                                      ^
main.cpp:48:33: error: no matching function for call to ‘iterate<bool>(const main()::<lambda(const int&)>&)’
   48 |     iterate< bool >( on_element );
      |                                 ^
main.cpp:10:6: note: candidate: ‘template<class Odds,const auto:12&)’
   10 | void iterate(
      |      ^~~~~~~
main.cpp:10:6: note:   template argument deduction/substitution Failed:
main.cpp:48:33: note:   candidate expects 2 arguments,1 provided
   48 |     iterate< bool >( on_element );
      |                                 ^
main.cpp:51:39: error: no matching function for call to ‘iterate<void,bool>(const main()::<lambda(const int&)>&)’
   51 |     iterate< void,bool >( on_element );
      |                                       ^
main.cpp:10:6: note: candidate: ‘template<class Odds,const auto:12&)’
   10 | void iterate(
      |      ^~~~~~~
main.cpp:10:6: note:   template argument deduction/substitution Failed:
main.cpp:51:39: note:   candidate expects 2 arguments,1 provided
   51 |     iterate< void,bool >( on_element );
      |                                       ^

有没有一种方法可以在C ++中实现? 也许有更好的编译时技术来实现所需的行为?

解决方法

template<
  bool Odds = false,bool Evens = false,bool Skip = false // or really,true: why pass skip if we won't use it?
>
void iterate(
  const auto & on_element,const auto & skip
)

并编写另一个重载:

template<
  bool Odds = false,bool Evens = false
> // no bool Skip; lack of arg is enough
void iterate(
  const auto & on_element
)
{
  iterate<Odds,Evens,false>(on_element);
}

然后将! is_same_v< Skip,void >替换为Skip,赔率/偶数类似。

static_assert( !Skip||!std::is_same_v<decltype(skip),const int&>,"You must pass a 2nd argument" );

对生活质量有好处。

,

在我看来,在这种情况下,您应该避免使用auto类型的参数。

我提出以下代码

#include <type_traits>
#include <iostream>
#include <set>

using namespace std;

template<
    bool Odds = true,bool Evens = true,typename Func,typename Skip = bool
>
void iterate(
    Func const & on_element,Skip const & skip = false
) {
    for ( int i = 0; i < 6; ++ i ) {
        if constexpr ( ! is_same_v< Skip,bool > ) {
            if ( skip.find( i ) != skip.end() )
                continue;
        }

        if ( i % 2 == 1 ) {
            if constexpr ( Odds )
                on_element( i );
        }
        else {
            if constexpr ( Evens )
                on_element( i );
        }

        static_assert(
            Odds || Evens,"Either odds or evens are required to get traversed"
        );
    }
}

int main() {
    const auto & on_element = []( const int & i ) {
        cout << "    " << i << endl;
    };

    cout << "Whole range:" << endl;
    iterate( on_element );

    cout << "Should skip specified elements:" << endl;
    iterate( on_element,std::set{ 1,2,3 } );

    cout << "Should traverse only evens:" << endl;
    iterate< false >( on_element );

    cout << "Should traverse only odds:" << endl;
    iterate< true,false >( on_element );

    // should NOT compile if uncomment:
    // iterate< false,false >( on_element );
}
,

也许简化

#include <type_traits>
#include <iostream>
#include <algorithm>
#include <array>

auto Odds = [](auto&& i) { return i % 2 == 0; };
auto Evens = [](auto&& i) { return i % 2 == 1; };
auto None = [](auto&&) { return false; };

template<class...Ts>
struct These
{
    constexpr These(Ts... args)
    : args_ { args... }
    {}

    template<class Arg>
    bool operator()(Arg&& i) const
    {
        return std::any_of(
            std::begin(args_),std::end(args_),[i](auto x) { return x == i; }
        );
    }

    std::array<std::common_type_t<Ts...>,sizeof...(Ts)> args_;
};

template<
    typename Skip = decltype(None)
>
void iterate(
    const auto & on_element,Skip&& skip = Skip()
) {
    for ( int i = 0; i < 6; ++ i ) {
        if (skip(i))
            continue;
        std::cout << i << ",";
    }
    std::cout << std::endl;
}

int main() {
    const auto & on_element = []( const int & i ) {
        std::cout << "    " << i << std::endl;
    };

    std::cout << "Whole range:" << std::endl;
    iterate( on_element );

    std::cout << "Should skip specified elements:" << std::endl;
    iterate( on_element,These( 1,3 ));

    std::cout << "Should traverse only evens:" << std::endl;
    iterate( on_element,Evens);

    std::cout << "Should traverse only odds:" << std::endl;
    iterate( on_element,Odds );
}

预期输出:

Whole range:

0,1,3,4,5,Should skip specified elements:

0,Should traverse only evens:

0,Should traverse only odds:

1,
,

如果您需要使用iterate版本的参数,则必须实现一个参数。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其他元素将获得点击?
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。)
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbcDriver发生异常。为什么?
这是用Java进行XML解析的最佳库。
Java的PriorityQueue的内置迭代器不会以任何特定顺序遍历数据结构。为什么?
如何在Java中聆听按键时移动图像。
Java“Program to an interface”。这是什么意思?