30

For example I wanted to have a variable of type auto because I'm not sure what type it will be.

When I try to declare it in class/struct declaration it's giving me this error:

Cannot deduce auto type. Initializer required

Is there a way around it?

struct Timer {

    auto start;

};
Oleksiy
  • 37,477
  • 22
  • 74
  • 122

6 Answers6

34

You can, but you have to declare it static and const:

struct Timer {
    static const auto start = 0;
};

A working example in Coliru.

With this limitation, you therefore cannot have start as a non-static member, and cannot have different values in different objects.

If you want different types of start for different objects, better have your class as a template

template<typename T>
struct Timer {
    T start;
};

If you want to deduce the type of T, you can make a factory-like function that does the type deduction.

template<typename T>
Timer<typename std::decay<T>::type> MakeTimer(T&& startVal) {   // Forwards the parameter
   return Timer<typename std::decay<T>::type>{std::forward<T>(startVal)};
}

Live example.

Mark Garcia
  • 17,424
  • 4
  • 58
  • 94
  • 1
    Is there anything fundamental that prevents auto non static members from being allowed in the standard assuming they are initialized at point of declaration ? – user3882729 Jul 31 '22 at 06:07
  • @user3882729 Imo an `auto` member would make it pretty unclear that it's actually a template, unlike a function template which just have `auto` at it's first line. – apple apple Mar 24 '23 at 16:12
5

This is what the C++ draft standard has to say about using auto for member variables, in section 7.1.6.4 auto specifier paragraph 4:

The auto type-specifier can also be used in declaring a variable in the condition of a selection statement (6.4) or an iteration statement (6.5), in the type-specifier-seq in the new-type-id or type-id of a new-expression (5.3.4), in a for-range-declaration, and in declaring a static data member with a brace-or-equal-initializer that appears within the member-specification of a class definition (9.4.2).

Since it must be initialized this also means that it must be const. So something like the following will work:

struct Timer
{
  const static int start = 1;
}; 

I don't think that gets you too much though. Using template as Mark suggests or now that I think about it some more maybe you just need a variant type. In that case you should check out Boost.Variant or Boost.Any.

Lightness Races in Orbit
  • 378,754
  • 76
  • 643
  • 1,055
Shafik Yaghmour
  • 154,301
  • 39
  • 440
  • 740
4

If you declare a class in a lambda expression, you can infer the types of member variables using decltype:

#include <iostream>
#include <vector>
#include <string>
using namespace std;

auto generic_class = [](auto width1, auto height1) {
    class local_class {
        public:
        decltype(width1) width;
        decltype(height1) height;
    } local;
    local.width = width1;
    local.height = height1;
    return local;
};

int main()
{
    auto obj1 = generic_class(3,std::string("Hello!"));
    auto obj2 = generic_class(std::vector<int>{1,2},true);
    cout << obj1.height << "\n";
    cout << obj2.width[0] << "\n";
    return 0;
}
Anderson Green
  • 30,230
  • 67
  • 195
  • 328
2

No. Each constructor could have its own initializer for start, so there could be no consistent type to use.

If you do have a usable expression, you can use that:

struct Timer {

   Foo getAFoo();

   delctype(Timer().getAFoo().Bar()) start;

   Timer() : start(getAFoo().Bar()) { /***/ }
};
MSalters
  • 173,980
  • 10
  • 155
  • 350
  • 2
    Is there any way of writing this without repeating `getAFoo().Bar()`? – Eric Jun 22 '18 at 17:37
  • 1
    @Eric: Of course, just add a member `auto getAFooBar() { return getAFoo().Bar(); }` and use that instead. The example was showing off that even more complex variants still work. – MSalters Jun 22 '18 at 19:09
1

Actually, it would be nice, if a future version of the C++ standard allowed auto also on non-static members, if an initializer is present, as in this simple example:

class C {
    auto a { 0.0 };
    auto b { 3U };
};

This would be equivalent to:

class C {
    decltype(0.0) a { 0.0 };
    decltype(3U) b { 3U };
};

and would save some typing in certain cases, especially, where the initializing expressions are not as simple as here. Of course, the in-class initializers can later be overridden in constructors, but for the typing of the class members, the in-class initializers should take precedence.

Kai Petzke
  • 2,150
  • 21
  • 29
0

Indirectly, provided that you don't reference a member of the class.

This can also now be achieved through deduction guides, these were introduced in C++17 and have recently (finally) support in VC++ has been added (clang and GCC already had it).

https://en.cppreference.com/w/cpp/language/class_template_argument_deduction

For example:

template <typename>
struct CString;

template <typename T, unsigned N>
struct CString<std::array<T, N>>
{
    std::array<T, N> const Label;

    CString(std::array<T, N> const & pInput) : Label(pInput) {}
};

template <typename T, std::size_t N>
CString(std::array<T, N> const & pInput) -> CString<std::array<T, N>>;

https://godbolt.org/z/LyL7UW

This can be used to deduce class member types in a similar manner to auto. Although the member variables need to be Dependant somehow on the constructor arguments.

David Ledger
  • 2,033
  • 1
  • 12
  • 27
  • This doesn't seem related, really. There is no deduction of the member's type here. Rather, the member is explicitly typed, although it just so happens that said type depends on template arguments. What done here is deducing those template arguments from the constructor call, not the type of the member. The type of the member is set in stone by that of the class; it's not automatic at all. – underscore_d Oct 05 '18 at 21:46
  • The member type is deduced from the deduction guide, not explicitly typed. The question specifically said "I wanted to have a variable of type auto because I'm not sure what type it will be." Deduction guides address this, provided that the constructor can be used for deduction (which is likely but not garenteed). This is actually similar to the top rated answers factory function. So its not just me who thinks this may assist the questioner. – David Ledger Oct 09 '18 at 02:10