#include <iostream>
#include <utility>
#include <tuple>

bool validate (std::string s) { return !s.empty(); }
bool validate (const void *p) { return p; }

template <typename Tuple>
bool validate (Tuple param) {
    if (validate(std::get<0>(param))) return true;
    #ifndef NDEBUG
    std::cout << "Invalid: " << std::get<1>(param) << std::endl;
    std::get<2>(param)();
    #endif
    return false;
}

bool validate () { return true; }

template <typename T, typename... Params>
bool validate (T param, Params... params) {
    return validate(param) & validate(params...);
}

void foo (std::string appPath, std::string appName) {
    bool result
        = validate(
              std::make_tuple(appPath, "ApplicationPath",
                              [&](){ appPath = "defaultPath"; }),
              std::make_tuple(appName, "ApplicationName",
                              [&](){ appName = "defaultName"; })
                   //...
                  );
    if (result) std::cout << "all good!\n";
    else std::cout << "bad param!\n";

    std::cout << "path:" << appPath << ", name:" << appName << std::endl;
}

int main () {
     foo(std::string(), std::string());
     foo(std::string(), "world");
     foo("Hello", std::string());
     foo("Hello", "world");
}
