r/cpp•
Octoploid

gcc trunk now accepts std::tuple t{1, true, "test"s};

 % cat tuple.cpp
#include <string>
#include <tuple>
using namespace std::literals::string_literals;
std::tuple t{1, true, "test"s};
 % g++ -c -std=c++1z tuple.cpp
 %    

Posted Oct 7, 2016, 11:25 AM UTC

5225
SuperV1234•

This does not work :(

(EDIT: it's a bug)

#include <iostream>

template <typename TF>
struct scope_guard : TF
{
    scope_guard(TF f) : TF{std::move(f)} { }
    ~scope_guard() { (*this)(); }
};

int main()
{
    scope_guard sg0{[]{ std::cout << "hi\n"; }};
}

prog.cc:6:5: error: 'scope_guard(TF)-> scope_guard<TF> [with TF = main()::<lambda()>]', declared using local type 'main()::<lambda()>', is used but never defined [-fpermissive]
 scope_guard(TF f) : TF{std::move(f)} { }
 ^~~~~~~~~~~
6
SuperV1234•
5
Nomto•

One functionally equivalent thing that I use currently and which works in c++11 is the following:

#include <iostream>
#include <utility>

template<typename T>
class scope_guard
{
public:
    scope_guard(T func) : m_func(std::move(func)) {}
    ~scope_guard() { m_func(); }
private:
    T m_func;
};

template<typename T>
scope_guard<T> make_scope_guard(T t)
{
    return scope_guard<T>(t);
}

int main()
{
    auto  sg0 = make_scope_guard( [] { std::cout << "hi\n"; } );
}

edit: don't want to take credit, it's taken from this codebase.

2
RotsiserMhoC++14 Embedded Developer•

This "make idiom" works in many situations where type deduction would be convenient. It's a great fallback.

3
ti-gars•

Correct me if I'm wrong but this could be calling your lambda twice since copy elision is not guaranteed yet. You should put some force inline attribute there.

3
[deleted]•

[deleted]

1
dodheim•

scope_guard will execute even if an exception is thrown. Think try..finally.

7
SuperV1234•

Not only that, but in some cases it is required to avoid complex control flow or gotos. Example from my code where scope guard is necessary as f_step could return void (would need an explicit specialization otherwise).

2
tomilovanatoliy•

There is a way to call multiple of bases:

#include <utility>

template< typename index_sequence, typename ...F >
struct scope_guard_base;

template< std::size_t I, typename F >
struct scope_guard_wrapper { F f; };

template< std::size_t I, typename F >
F & get(scope_guard_wrapper< I, F > * sg)
{
    return sg->f;
}


template < std::size_t ...I, typename ...F >
struct scope_guard_base< std::index_sequence< I... >, F... >
    : scope_guard_wrapper< I, F >...
{
    using base = scope_guard_base;
    scope_guard_base(F &&... f) : scope_guard_wrapper< I, F >{std::forward< F >(f)}... { ; }
    ~scope_guard_base() { (get< (sizeof...(I) - 1 - I) >(this)(), ...); }
};

template< typename ...F >
struct scope_guard
    : scope_guard_base< std::index_sequence_for< F... >, F... >
{

        scope_guard(F &&... f) : scope_guard::base{std::forward< F >(f)...} { ; }

};

#include <iostream>

template< std::size_t I >
struct F
{

    F() { std::cout << I << std::endl; }

    void operator () () { std::cout << I << std::endl; }

};

int main()
{
    F< 0 > f{};
    scope_guard _{f, F< 1 >{}, F< 2 >{}};
}
1
C5H5N5O•

Just as a side note, I personally think using TF::operator()() is much more explicit and easier to read than (*this)() :).

-3
A_Seat_For_One•

It doesn't deduce the parameter if the variable is initialized with an initalizer-list. Is it a bug or does the standard enforce it like that?

Example:

vector vec = {1,2,3,4};

5
dodheim•

I don't think initializer_lists are ever deducible.

5
wichtounet•

Indeed, they are not

1
tongari95•

You can use this form though:

std::vector v{{1, 2, 3, 4}};
5
redditsoaddicting•

Just keep in mind this introduces a potential future problem:

std::vector v{{"abc", "def"}};

for (const auto&x : v) {
    std::cout << x << " "; // abc def
}

Someone comes along and decides that instead of using "abc"s and "def"s, they'll make this a std::vector<std::string>:

std::vector<std::string> v{{"abc", "def"}}; // UB - crashes on WandBox

for (const auto&x : v) {
    std::cout << x << " "; 
}
3
dodheim•
std::vector<std::string> v{{"abc", "def"}}; // UB

Why is this UB?

1
redditsoaddicting•

There was a good SO question on it. It uses the stupid iterator pair constructor for std::string, passing one string initialized with the pointers for these string literals treated as iterators^1. Removing one set of braces would prevent this, and it wasn't until now that I found a plausible reason for accidentally having double braces.


^1 :

std::vector<std::string> v{    {  "abc", "def"  }    };
                               ^^^^one string^^^^
                          ^^^^^^initializer list^^^^^^
3
scatters•

You need a deduction guide for that, so until libstdc++ add one for vector. Of course, while playing around you can write one yourself, notwithstanding the UB.

1
markand67•

Totally awesomesauce :)

No more std::make_tuple.

4
redditsoaddicting•

Careful.

int arr[] = {0};
std::tuple t{arr}; // error
auto t2 = std::make_tuple(arr); // tuple<int*>

The tuple constructor doesn't decay arguments.

int i = 0;
std::tuple t{std::ref(i)}; // tuple<reference_wrapper<int>>
auto t2 = std::make_tuple(std::ref(i)); // tuple<int&>

static_assert(std::is_same<decltype(t), decltype(t2)>{}); // fails

The tuple constructor doesn't unwrap std::reference_wrapper into a reference.

6
gracicot•

Is it considered an issue right now? Seems like std::tuple is missing some deduction guide.

3
redditsoaddicting•

You could argue either way. There will probably be some discussion on it if there hasn't been already.

3
SuperV1234•

Any online compiler supporting it yet?

EDIT: wandbox does

1
dodheim•
3
blelbachCppCon | C++Now | HPX•

Oh yah, heard this on IRC a few days ago. Very exciting!

1
[deleted]•

[removed]

-3
[deleted]•

[removed]

2