1

Consider the following code snippet:

template<unsigned... IDs>
class MyClass{
public:
    static const std::array<unsigned, sizeof...(IDs)> ids { IDs... };
    PinIDs() = default;
};

Then use the class as:

MyClass<1,5,7,9> myClass;

The Objective would be to have ids with a size of 4, and contain the values: (1,5,7,9) respectively.

Is this type object possible or would I have to remove the static qualifier? If not how would one write this with the static qualifier. The object needs to be default constructible.


EDIT:

I tried Apple Apple's first solution and with MS Visual Studio 2017 CE on Win7 I got this compiler error:

 1>------ Build started: Project: PracticeMath, Configuration: Debug Win32 ------
1>stdafx.cpp
1>PracticeMath.cpp
1>c:\users\skilz80\documents\visual studio 2017\projects\practicemath\practicemath\practicemath.cpp(33): error C2988: unrecognizable template declaration/definition
1>c:\users\skilz80\documents\visual studio 2017\projects\practicemath\practicemath\practicemath.cpp(33): error C2143: syntax error: missing ';' before '<'
1>c:\users\skilz80\documents\visual studio 2017\projects\practicemath\practicemath\practicemath.cpp(33): error C2059: syntax error: '<'
1>c:\users\skilz80\documents\visual studio 2017\projects\practicemath\practicemath\practicemath.cpp(33): error C2039: 'ids': is not a member of '`global namespace''
1>c:\users\skilz80\documents\visual studio 2017\projects\practicemath\practicemath\practicemath.cpp(33): error C2143: syntax error: missing ';' before '{'
1>c:\users\skilz80\documents\visual studio 2017\projects\practicemath\practicemath\practicemath.cpp(33): error C2447: '{': missing function header (old-style formal list?)
1>c:\users\skilz80\documents\visual studio 2017\projects\practicemath\practicemath\practicemath.cpp(38): error C2065: 'myId': undeclared identifier
1>c:\users\skilz80\documents\visual studio 2017\projects\practicemath\practicemath\practicemath.cpp(39): error C2065: 'myId': undeclared identifier
1>c:\users\skilz80\documents\visual studio 2017\projects\practicemath\practicemath\practicemath.cpp(40): error C2065: 'myId': undeclared identifier
1>c:\users\skilz80\documents\visual studio 2017\projects\practicemath\practicemath\practicemath.cpp(44): error C2065: 'c': undeclared identifier
1>Done building project "PracticeMath.vcxproj" -- FAILED.
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========

With full original source like this:

#include <iostream>
#include <array>

template<unsigned... IDs>
class PinIDs{
public:
    static const std::array<unsigned, sizeof...(IDs)> ids;

    PinIDs() = default;

    const unsigned& operator[]( unsigned idx ) const {
        return ids[idx];
    }
};

template<unsigned... IDs>
const std::array<unsigned, sizeof...(IDs)> PinIDs<IDs...>::ids { IDs... };

int main() {
    PinIDs<4, 17, 19> myId;

    std::cout << myId[0] << " ";
    std::cout << myId[1] << " ";
    std::cout << myId[2] << " ";

    std::cout << "\nPress any key and enter to quit." << std::endl;
    char c;
    std::cin >> c;

    return 0;
}

Thanks to StoryTeller bringing up the fact that when I tried to apply Apple Apple's 1st method I accidently mixed up MyClass as opposed to the actual name of the class in my solution - project. Once I corrected that it does compile, build and run as expected.

10
  • 1
    Did you try it? Commented Dec 20, 2017 at 6:36
  • Yes; but was having trouble... don't know if the template syntax business, or just because of using static... Commented Dec 20, 2017 at 6:36
  • If you "have trouble", paste the error you get Commented Dec 20, 2017 at 6:41
  • @PasserBy I understand the errors; it's just the template syntax that gets me at times... Commented Dec 20, 2017 at 6:43
  • btw, are you bound to a specific C++ version? Commented Dec 20, 2017 at 6:46

3 Answers 3

3

you can try this


#include <array>

template<unsigned... IDs>
class MyClass{
public:
   static const std::array<unsigned, sizeof...(IDs)> ids;
   MyClass() = default;
};

template<unsigned... IDs>
const std::array<unsigned, sizeof...(IDs)> MyClass<IDs...>::ids {IDs...};

int main(){
   MyClass<1,5,7,9> myClass;
   return myClass.ids[0];
}

or use constexpr/inline (both need c++17)


#include <array>
template<unsigned... IDs>
class MyClass{
public:
    //static constexpr std::array<unsigned, sizeof...(IDs)> ids{IDs...};//or this
    static inline const std::array<unsigned, sizeof...(IDs)> ids{IDs...};
    MyClass() = default;
};

int main(){
MyClass<1,5,7,9> myClass;
    return myClass.ids[0];
}
Sign up to request clarification or add additional context in comments.

7 Comments

Hmm pretty close; I was able to get my class to work as expected without the static qualifier. Just that when I tried to make the member variable of static type; is where I was getting into a bit of trouble.
@FrancisCugler - This is how you'd do it with a static member. It need to be defined outside the class.
Also I would like to add a operator[] to the class that will index directly into the array so I don't have to use object.ids[] or MyClass::ids[]
I know that much; same as having const static member variables; I've used them before. Just not with templates... and that is where I was struggling because of the syntax.
@FrancisCugler maybe your compiler not support it yet, here is a working example
|
1

Refer to @apple apple's answer for the basics. I'll just add the C++17 way to do it. Which is quite close to your original attempt. Just add an inline specifier to the variable:

template<unsigned... IDs>
class MyClass{
public:
    static inline const std::array<unsigned, sizeof...(IDs)> ids{ { IDs... } };
    MyClass() = default;
};

Now the declaration can double as a definition. Oh, and mind the braces. std::array needs to be initialized as an aggregate. So one pair of {} for the std::array, and one for the internal raw array it holds.

5 Comments

hmm I knew you could use inline on member functions; just didn't know you could use it on member variables...
@FrancisCugler - Only from C++17 onward.
Oh okay, I see; a new language feature that MS Visual Studio is probably lacking on...
@FrancisCugler - Depends on your MSVC version, as ever :)
yeah my version states C2433: ... : 'inline' not permitted on data declarations...
0

why don't you just try it with online compiler, supporting c++17?

template<unsigned... IDs>
class MyClass{
public:
    static constexpr std::array<unsigned, sizeof...(IDs)> ids { IDs... };
    MyClass() = default;
};

works fine. You don't need static const inline for variables, which are computed at compile time, just use static constexpr

5 Comments

are constexpr default constructible?
@FrancisCugler, constexpr values are computed at compile-time. static fields in no way interfere with type traits of a class (including default constructibility).
"constexpr values are computed" - No, they may be computed at compile time. And even then the array is still likely gonna occupy storage. Because operator[] is an ODR-use.
@StoryTeller, occupies storage doesn't imply not computed at compile time. Values of this array (along with its size) are defined at compile-time and may be statically checked.
@AndreiR. - I never said the storage precludes it. The storage argument is to clarify that it isn't something that exists "just at compile time". And yes, the values may be used when compiling. Emphasis on may. constexpr is great, but sometimes it fails us. Only way to know is to examine the generated object files.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.