Вы уже выбрали ответ, но я все равно возьму вызов:
#include <iostream>
#include <type_traits>
#include <utility>
template < typename RollbackLambda >
class ScopeGuard;
template < typename RollbackLambda >
auto make_ScopeGuard( RollbackLambda &&r ) -> ScopeGuard<typename
std::decay<RollbackLambda>::type>;
template < typename RollbackLambda >
class ScopeGuard
{
// The input may have any of: cv-qualifiers, l-value reference, or both;
// so I don't do an exact template match. I want the return to be just
// "ScopeGuard," but I can't figure it out right now, so I'll make every
// version a friend.
template < typename AnyRollbackLambda >
friend
auto make_ScopeGuard( AnyRollbackLambda && ) -> ScopeGuard<typename
std::decay<AnyRollbackLambda>::type>;
public:
using lambda_type = RollbackLambda;
private:
// Keep the lambda, of course, and if you really need it at the end
bool committed;
lambda_type rollback;
// Keep the main constructor private so regular creation goes through the
// external function.
explicit ScopeGuard( lambda_type rollback_action )
: committed{ false }, rollback{ std::move(rollback_action) }
{}
public:
// Do allow moves
ScopeGuard( ScopeGuard &&that )
: committed{ that.committed }, rollback{ std::move(that.rollback) }
{ that.committed = true; }
ScopeGuard( ScopeGuard const & ) = delete;
// Cancel the roll-back from being called.
void commit() { committed = true; }
// The magic happens in the destructor.
// (Too bad that there's still no way, AFAIK, to reliably check if you're
// already in exception-caused stack unwinding. For now, we just hope the
// roll-back doesn't throw.)
~ScopeGuard() { if (not committed) rollback(); }
};
template < typename RollbackLambda >
auto make_ScopeGuard( RollbackLambda &&r ) -> ScopeGuard<typename
std::decay<RollbackLambda>::type>
{
using std::forward;
return ScopeGuard<typename std::decay<RollbackLambda>::type>{
forward<RollbackLambda>(r) };
}
template < typename ActionLambda, typename RollbackLambda >
auto make_ScopeGuard( ActionLambda && a, RollbackLambda &&r, bool
roll_back_if_action_throws ) -> ScopeGuard<typename
std::decay<RollbackLambda>::type>
{
using std::forward;
if ( not roll_back_if_action_throws ) forward<ActionLambda>(a)();
auto result = make_ScopeGuard( forward<RollbackLambda>(r) );
if ( roll_back_if_action_throws ) forward<ActionLambda>(a)();
return result;
}
int main()
{
auto aa = make_ScopeGuard( []{std::cout << "Woah" << '\n';} );
int b = 1;
try {
auto bb = make_ScopeGuard( [&]{b *= 2; throw b;}, [&]{b = 0;}, true );
} catch (...) {}
std::cout << b++ << '\n';
try {
auto bb = make_ScopeGuard( [&]{b *= 2; throw b;}, [&]{b = 0;}, false );
} catch (...) {}
std::cout << b++ << '\n';
return 0;
}
// Should write: "0", "2", and "Woah" in that order on separate lines.
Вместо того, чтобы создавать функции создания и конструктор, вы ограничиваетесь только функциями создания, причем основным конструктором является private
. Я не мог понять, как ограничить экземпляры friend
-ed только теми, которые связаны с текущим параметром шаблона. (Возможно, потому, что параметр упоминается только в возвращаемом типе.) Возможно, на этом сайте может быть исправлено исправление. Поскольку первое действие не нужно хранить, оно присутствует только в функциях создания. Существует флаг Boolean, если флаг throw
от первого действия вызывает возврат или нет.
Часть std::decay
разделяет как cv-квалификаторы, так и ссылочные маркеры. Но вы не можете использовать его для этой общей цели, если тип ввода является встроенным массивом, так как он будет применять преобразование между массивами и указателями.
Вы можете получить эти имена с помощью XPath, например и используйте их как:
byte[] data = new ASCIIEncoding().GetBytes("textBoxName1=blabla");
HttpWebRequest httpWebRequest = (HttpWebRequest)WebRequest.Create("http://localhost/myservlet");
httpWebRequest.Method = "POST";
httpWebRequest.ContentType = "application/x-www-form-urlencoded";
httpWebRequest.ContentLength = data.Length;
Stream myStream = httpWebRequest.GetRequestStream();
myStream.Write(data,0,data.Length);
myStream.Close();
var request = WebRequest.Create("http://foo");
request.Method = "POST";
request.ContentType = "application/x-www-form-urlencoded";
using (var writer = new StreamWriter(request.GetRequestStream()))
{
writer.Write("field=value");
}
Похоже, вам нужно будет получить страницу с помощью HttpWebRequest и проанализировать содержимое соответствующего HttpWebResponse, чтобы узнать имена текстовых полей. Затем вы отправляете значения на страницу с помощью другого HttpWebRequest.
Итак, в основном, что вам нужно сделать, это следующее: