Thread: Function template with a class template type arg

  1. #1
    Registered User
    Join Date
    Dec 2006
    Location
    Canada
    Posts
    3,229

    Question Function template with a class template type arg

    Hello!

    I am trying to write a function template that takes a class template (with non-type arguments), and my brain (and Google) can't seem to find the right syntax for this.

    A few lines of code is worth a thousand words, so here is a simplified example:
    Code:
    #include <iostream>
    
    template <int X, int Y> struct A {};
    
    template<A<int X, int Y>>
    void f() { std::cout << X << ", " << Y << std::endl; }
    
    int main() {
        f<A<1, 2>>();
    }
    How do I make this work?

    Error:
    Code:
    5:24: error: wrong number of template arguments (1, should be 2)
    3:32: error: provided for 'template<int X, int Y> struct A'
    6:8: error: two or more data types in declaration of 'f'
    6:10: error: expected '>' before '{' token
    6:10: error: expected unqualified-id before '{' token
     In function 'int main()':
    9:5: error: 'f' was not declared in this scope
    9:13: error: expected primary-expression before '>' token
    9:16: error: expected primary-expression before ')' token
    Runnable example: C++ Shell

    Thanks!

    PS: Not sure if any of the regulars from years ago are still here, but if so, hi! I used to be very active here about 10 years ago... a lot has changed but coming back here is hitting me with nostalgia!

  2. #2
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Hello, long time no see. I'm afraid that I don't have a direct solution, but I'm wondering what's your use case. Like, if you're going to be doing something like this:
    Code:
    A<1, 2> a;
    f<decltype(a)>();
    then presumably you'll be passing a around a bit, and so perhaps the cost of the reference involved in doing this:
    Code:
    A<1, 2> a;
    f(a);
    would be insignificant, even if the compiler doesn't figure out that that can be eliminated, so this more common solution might be acceptable.

    But if you're explicitly doing this:
    Code:
    f<A<1, 2>>();
    then why not just write:
    Code:
    f<1, 2>();
    since you always intend the class template to be A?
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  3. #3
    Registered User
    Join Date
    Dec 2006
    Location
    Canada
    Posts
    3,229
    Hey I remember you!

    Quote Originally Posted by laserlight View Post
    Code:
    f<A<1, 2>>();
    then why not just write:
    Code:
    f<1, 2>();
    since you always intend the class template to be A?
    I am indeed doing something like that, and the reason why I don't want to specify the template parameters directly is because I want to define a bunch of constants that are essentially tuples of the template parameters.

    I feel at this point it's probably easier to explain my actual application: this is for the register read/write functions in embedded code. The functions are for reading from / writing to register fields, which are defined by an address, a bit offset, and a bit length.

    What I want to do is this:
    Code:
    template <uint32_t Addr, uint8_t StartBit, uint8_t NumBits> struct Field {};
    
    using FieldA = Field<0xAA, 3, 5>;
    using FieldB = Field<0xAB, 5, 7>;
    ... etc
    And I want to be able to use them like:
    Code:
    uint32_t val = ReadField<FieldA>();

  4. #4
    Registered User
    Join Date
    Dec 2017
    Posts
    1,633
    @laserlight, Do you know why it's saying "error: wrong number of template arguments (1, should be 2)"?

    @cyberfish, Not exactly sure what you're trying to do, but here's another possibility:
    Code:
    #include <iostream>
     
    template <int VX, int VY> struct A {
        constexpr static int X{VX}, Y{VY};
    };
     
    template <typename T> void f() {
        std::cout << T().X << ',' << T().Y << '\n';
    }
     
    int main() {
        f<A<1,2>>();
    }
    EDIT: I just saw that you posted again! Haven't processed it yet....
    Last edited by john.c; 12-29-2021 at 07:07 PM.
    A little inaccuracy saves tons of explanation. - H.H. Munro

  5. #5
    Registered User
    Join Date
    Dec 2017
    Posts
    1,633
    It looks like it might work.
    Code:
    #include <iostream>
     
    uint32_t a[2]
    {
        0x11223344,  // 00010001 00100010 00110011 01000100
                     //                            ^^^^^    FieldA = 8
        0x55667788   // 01010101 01100110 01110111 10001000
                     //                       ^^^^ ^^^      FieldB = 60
    };
     
    template <uint32_t Addr, uint8_t StartBit, uint8_t NumBits>
    struct Field
    {
        constexpr static uint32_t addr{Addr};
        constexpr static uint8_t  startBit{StartBit};
        constexpr static uint8_t  numBits{NumBits};
    };
     
    using FieldA = Field<0, 3, 5>;
    using FieldB = Field<1, 5, 7>;
     
    template<typename T>
    uint32_t ReadField()
    {
        constexpr T v;
        return (a[v.addr] >> v.startBit) & ((1 << v.numBits) - 1);
    }
     
    int main()
    {
        std::cout << ReadField<FieldA>() << '\n';
        std::cout << ReadField<FieldB>() << '\n';
    }
    A little inaccuracy saves tons of explanation. - H.H. Munro

  6. #6
    Registered User
    Join Date
    Dec 2006
    Location
    Canada
    Posts
    3,229
    Quote Originally Posted by john.c View Post
    It looks like it might work.
    Code:
    #include <iostream>
     
    uint32_t a[2]
    {
        0x11223344,  // 00010001 00100010 00110011 01000100
                     //                            ^^^^^    FieldA = 8
        0x55667788   // 01010101 01100110 01110111 10001000
                     //                       ^^^^ ^^^      FieldB = 60
    };
     
    template <uint32_t Addr, uint8_t StartBit, uint8_t NumBits>
    struct Field
    {
        constexpr static uint32_t addr{Addr};
        constexpr static uint8_t  startBit{StartBit};
        constexpr static uint8_t  numBits{NumBits};
    };
     
    using FieldA = Field<0, 3, 5>;
    using FieldB = Field<1, 5, 7>;
     
    template<typename T>
    uint32_t ReadField()
    {
        constexpr T v;
        return (a[v.addr] >> v.startBit) & ((1 << v.numBits) - 1);
    }
     
    int main()
    {
        std::cout << ReadField<FieldA>() << '\n';
        std::cout << ReadField<FieldB>() << '\n';
    }
    Thanks yeah that does work.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Replies: 3
    Last Post: 01-30-2011, 04:28 PM
  2. template function v.s. template class
    By George2 in forum C++ Programming
    Replies: 3
    Last Post: 12-13-2007, 01:46 AM
  3. Replies: 4
    Last Post: 11-01-2006, 02:23 PM
  4. Function template in Class template?
    By Aidman in forum C++ Programming
    Replies: 3
    Last Post: 10-28-2003, 09:50 AM

Tags for this Thread