/* Copyright (C) 2013 - 2016, The libsigc++ Development Team
*
* This file is part of libsigc++.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see .
*/
// The purpose of this test case is threefold.
// - Test sigc::track_obj() and sigc::track_object().
// - Show that a slot with a C++11 lambda expression can be automatically
// disconnected when an object derived from sigc::trackable is deleted,
// provided sigc::track_obj() or sigc::track_object() is used.
// It shows that C++11 lambda expressions can replace the libsigc++ lambda
// expressions, which have been removed.
// See https://bugzilla.gnome.org/show_bug.cgi?id=672555
// - Test the code example in the documentation in sigc++/adaptors/track_obj.h.
//
// If test_track_obj writes nothing and the return code is 0, the test has passed.
// sigc::track_obj() is deprecated, but let's keep the test if possible.
// If libsigc++ is configured with -Dbuild-deprecated-api=false
// (--disable-deprecated-api), SIGCXX_DISABLE_DEPRECATED is defined in
// sigc++config.h. An undef at the start of this file has no effect.
#undef SIGCXX_DISABLE_DEPRECATED
#include "testutilities.h"
#include
#include
#include
namespace
{
std::ostringstream result_stream;
struct book : public sigc::trackable
{
explicit book(const std::string& name) : name_(name) {}
operator std::string&() { return name_; }
operator const std::string&() const { return name_; }
std::string name_;
};
struct bar_group4 : public sigc::trackable
{
};
class Functor1
{
public:
explicit Functor1(const bar_group4& bar) : bar_(bar) {}
std::string operator()(int i) { return (i < 0) ? "negative" : ((i > 0) ? "positive" : "zero"); }
protected:
// Don't make it private. clang++ does not like unused private data.
const bar_group4& bar_;
};
class Functor2
{
public:
Functor2(const bar_group4& bar, const book& aBook) : bar_(bar), aBook_(aBook) {}
std::string operator()(int i, const std::string& str) const
{
std::string result = (i < 0) ? "negative, " : ((i > 0) ? "positive, " : "zero, ");
result += str;
result += aBook_;
return result;
}
protected:
// Don't make it private. clang++ does not like unused private data.
const bar_group4& bar_;
private:
const book& aBook_;
};
// C++11 lamba expressions:
inline std::ostringstream&
operator<<(std::ostringstream& s, const book& b)
{
s << b.name_;
return s;
}
void
egon(std::string& str)
{
result_stream << "egon(string '" << str << "')";
str = "egon was here";
}
void
foo_group4(bar_group4&)
{
result_stream << "foo_group4(bar_group4&)";
}
} // end anonymous namespace
int
main(int argc, char* argv[])
{
auto util = TestUtilities::get_instance();
if (!util->check_command_args(argc, argv))
return util->get_result_and_delete_instance() ? EXIT_SUCCESS : EXIT_FAILURE;
sigc::slot sl1;
sigc::slot sl2;
{
bar_group4 bar4;
#ifndef SIGCXX_DISABLE_DEPRECATED
sl1 = sigc::track_obj(Functor1(bar4), bar4);
#else
sl1 = sigc::track_object(Functor1(bar4), bar4);
#endif
sl2 = sigc::track_object(Functor1(bar4), bar4);
result_stream << sl1(-2) << ", " << sl2(2);
util->check_result(result_stream, "negative, positive");
} // auto-disconnect sl1 and sl2
result_stream << sl1(-2) << ", " << sl2(2);
util->check_result(result_stream, ", ");
// Allocate on the heap. valgrind can then find erroneous memory accesses.
// (There should be none, of course.)
auto psl3 = new sigc::slot;
auto psl4 = new sigc::slot;
auto pbar4 = new bar_group4;
auto pbook4 = new book("A Book");
#ifndef SIGCXX_DISABLE_DEPRECATED
*psl3 = sigc::track_obj(Functor2(*pbar4, *pbook4), *pbar4, *pbook4);
#else
*psl3 = sigc::track_object(Functor2(*pbar4, *pbook4), *pbar4, *pbook4);
#endif
*psl4 = sigc::track_object(Functor2(*pbar4, *pbook4), *pbar4, *pbook4);
result_stream << (*psl3)(0, "Book title: ") << ", " << (*psl4)(1, "Title: ");
util->check_result(result_stream, "zero, Book title: A Book, positive, Title: A Book");
delete pbook4; // auto-disconnect *psl3 and *psl4
pbook4 = nullptr;
result_stream << (*psl3)(0, "Book title: ") << ", " << (*psl4)(1, "Title: ");
util->check_result(result_stream, ", ");
delete psl3;
psl3 = nullptr;
delete psl4;
psl4 = nullptr;
delete pbar4;
pbar4 = nullptr;
// C++11 lambda expressions:
// auto-disconnect
// If you want to auto-disconnect a slot with a C++11 lambda expression
// that contains references to sigc::trackable-derived objects, you must use
// sigc::track_obj() or sigc::track_object().
sigc::slot sl11;
sigc::slot sl12;
{
book guest_book("karl");
// no auto-disconnect
// sl1 = [&guest_book](std::ostringstream& stream){ stream << guest_book << "\n"; };
#ifndef SIGCXX_DISABLE_DEPRECATED
sl11 = sigc::track_obj(
[&guest_book](std::ostringstream& stream) { stream << guest_book; }, guest_book);
#else
sl11 = sigc::track_object(
[&guest_book](std::ostringstream& stream) { stream << guest_book; }, guest_book);
#endif
sl12 = sigc::track_object(
[&guest_book](std::ostringstream& stream) { stream << guest_book; }, guest_book);
sl11(result_stream);
sl12(result_stream);
util->check_result(result_stream, "karlkarl");
} // auto-disconnect sl11 and sl12
sl11(result_stream);
sl12(result_stream);
util->check_result(result_stream, "");
// auto-disconnect
sigc::slot sl21;
sigc::slot sl22;
{
book guest_book("karl");
// sl2 = [&guest_book] () { egon(guest_book); }; // no auto-disconnect
// sl2 = std::bind(&egon, std::ref(guest_book)); // does not compile (gcc 4.6.3)
#ifndef SIGCXX_DISABLE_DEPRECATED
sl21 = sigc::track_obj([&guest_book]() { egon(guest_book); }, guest_book);
#else
sl21 = sigc::track_object([&guest_book]() { egon(guest_book); }, guest_book);
#endif
sl22 = sigc::track_object([&guest_book]() { egon(guest_book); }, guest_book);
sl21();
sl22();
util->check_result(result_stream, "egon(string 'karl')egon(string 'egon was here')");
result_stream << static_cast(guest_book);
util->check_result(result_stream, "egon was here");
} // auto-disconnect sl21 and sl22
sl21();
sl22();
util->check_result(result_stream, "");
// Code example in the documentation sigc++/adaptors/track_obj.h.
// --------------------------------------------------------------
{
// struct bar : public sigc::trackable {} some_bar;
sigc::signal some_signal;
{
bar_group4 some_bar;
// some_signal.connect([&some_bar](){ foo_group4(some_bar); }); // no auto-disconnect
// some_signal.connect(sigc::bind(&foo_group4, std::ref(some_bar))); // auto-disconnects,
// but we prefer C++11 lambda
#ifndef SIGCXX_DISABLE_DEPRECATED
some_signal.connect(sigc::track_obj([&some_bar]() { foo_group4(some_bar); }, some_bar));
#else
some_signal.connect(sigc::track_object([&some_bar]() { foo_group4(some_bar); }, some_bar));
#endif
some_signal.connect(sigc::track_object([&some_bar]() { foo_group4(some_bar); }, some_bar));
some_signal.emit();
util->check_result(result_stream, "foo_group4(bar_group4&)foo_group4(bar_group4&)");
} // auto-disconnect the lambda expression
some_signal.emit();
util->check_result(result_stream, "");
}
return util->get_result_and_delete_instance() ? EXIT_SUCCESS : EXIT_FAILURE;
}