Here's my humble attempt, which uses a macro FOO to create a pair of the variable name and its value, and passes the arguments to a variadic function:
#include <utility>
#include <iostream>
#define FOO(var) std::make_pair(std::string(#var), var)
template <typename T>
void __deb(std::pair<std::string, T> arg) { std::cout << "[" << arg.first << "]:" << arg.second; }
template <typename... type>
void debug(std::pair<std::string, type> &&... args)
{
    (__deb(args), ...);
}
int main()
{
    int a = 1, b = 3;
    debug(FOO(a), FOO(b));
}
Demo
Alternatively, to avoid having a macro call FOO for each variable in debug, you could define debug as a macro that accepts #__VA_ARGS__ (string of arguments) and __VA_ARGS__ (argument values). Then parse each variable name and value:
#include <iostream>
#include <sstream>
#include <stdio.h>
#define debug(...) debug_print(#__VA_ARGS__,__VA_ARGS__)
template <typename T>
void __deb(std::istringstream &ss, T arg)
{
    //Extract name from stream
    std::string name;
    std::getline(ss, name, ',');
    //trim leading space
    const auto pos(name.find_first_not_of(" "));
    name.erase(0, pos);
    std::cout << "[" << name << "]:" << arg;
}
template <typename... type>
void debug_print(const char* names, type&&...args)
{
    std::istringstream ss(names);
    (__deb(ss, args), ...);
}
int main()
{
    int a = 1, b = 3, c = 4;
    debug(a, b, c);
}
Demo