Passing a variable as a template argument

前端 未结 6 1854
[愿得一人]
[愿得一人] 2020-11-28 11:02

I am working with a library which exposes an interface to work with. One of the functions of this library is like this :

template 
void modify()         


        
相关标签:
6条回答
  • 2020-11-28 11:34

    Since you asked for an answer using Boost.MPL:

    #include <boost/mpl/for_each.hpp>
    #include <boost/mpl/range_c.hpp>
    
    #include <iostream>
    
    template <int N>
    void modify()
    {
        std::cout << N << '\n';
    }
    
    // You need to wrap your function template in a non-template functor
    struct modify_t
    {
        template <typename N>
        void operator()(N)
        {
            modify<N::value>();
        }
    };
    
    int main()
    {
        namespace mpl = boost::mpl;
    
        mpl::for_each< mpl::range_c<int,0,10> >( modify_t() ); // prints 0 to 9
    }
    
    0 讨论(0)
  • 2020-11-28 11:37

    Without using struct or Boost it can also be done :

    #include <iostream>
    #include <utility>
    
    template <int a>
    void modify()
    {
        std::cout<<a<<",";
    }
    
    template<int i,size_t... t>
    constexpr inline void CT_for_impl(std::integer_sequence<size_t,t...>)
    {
        bool kai[]= { (modify<i+t>(), false)...};
    }
    
    template<int i,int n>
    constexpr inline void CT_for()
    {
        CT_for_impl<i>(std::make_index_sequence<n-i+1>());
    }
    
    int main()
    {
        CT_for<-5,5>();
        return 0;
    }
    
    0 讨论(0)
  • 2020-11-28 11:44

    solution to error: 'i' cannot appear in constant-expression for the above problem

    To read about constexpr click this link

    #include <iostream>
    using namespace std;
    
    template <typename T>
    void modify(T a)
    {
        cout<<a<<endl;  //to check if its working 
    }
    
    
    //func converts int a into const int a
    constexpr int func(int a)
    {
        return a;
    }
    
    int main(){
        for(int i=0; i<10; i++){
            modify(func(i));//here passing func(i) returned value which can be used as template argument now as it is converted to constexpr    
    }
        return 0;
    }
    
    0 讨论(0)
  • 2020-11-28 11:50
    1. "Why can't compiler evaluate i at compile time?"

      That would defeat the purpose of templates. Templates are there for the case where the source code looks the same for some set of cases, but the instructions the compiler needs to generate are different each time.

    2. "Is there any other to achieve the objective I am trying to achieve without changing the API interface?"

      Yes, look at Boost.MPL.

      However I suspect the right answer here is that you want to change the API. It depends on the internals of the modify function. I know you have it's source, because templates must be defined in headers. So have a look why it needs to know i at compile time and if it does not, it would be best to replace (or complement if you need to maintain backward compatibility) it with normal function with parameter.

    0 讨论(0)
  • 2020-11-28 11:52

    Given you want to call the functions at run-time by their index and you can't change the API, you can consider type-erasure:

    std::vector<std::function<void(int)> > func;
    func.push_back(modify<1>);
    func.push_back(modify<2>);
    //... and so on ...
    func.push_back(modify<10>);
    
    for(int i=0; i<10; ++i)
    {
        func[i]();  //calls modify<i+1>();
    }
    

    Some points to mention:

    • That's not what templates are primarily for, but it's a way to bring a static library to the run-time world. The basic requirement for this is that one works with homogeneous types (--if modify<7>() would return, say, a std::string the whole approach would break).
    • The previous solution using type-erasure has an overhead. One can maybe get it faster by using function pointers, but still it will always be slower than calling the functions at compile time.
    • One can (and should) also wrap the push_backs into another iterative static function to avoid the manual calls.
    0 讨论(0)
  • 2020-11-28 11:55

    What is the value of i (that is not a constant) at compile time? There is no way to answer unless executing the loop. But executing is not "compiling" Since there is no answer, the compiler cannot do that.

    Templates are not algorithm to be executed, but macros to be expanded to produce code. What you can do is rely on specialization to implement iteration by recursion, like here:

    #include <iostream>
    
    template<int i>
    void modify()
    { std::cout << "modify<"<<i<<">"<< std::endl; }
    
    template<int x, int to>
    struct static_for
    {
        void operator()() 
        {  modify<x>();  static_for<x+1,to>()(); }
    };
    
    template<int to>
    struct static_for<to,to>
    {
        void operator()() 
        {}
    };
    
    
    int main()
    {
        static_for<0,10>()();
    }
    

    Note that, by doing this, you are, in fact, instantiating 10 functions named modify<0> ... modify<9>, called respectively by static_for<0,10>::operator() ... static_for<9,10>::operator().

    The iteration ends because static_for<10,10> will be instantiated from the specialization that takes two identical values, that does nothing.

    0 讨论(0)
提交回复
热议问题