Особое ограничение, что должен быть только один конструктор. Вот самое близкое, о чем я могу подумать:
#include <iostream>
// cheap and cheerful Boost.Variant
struct StringOrInt {
char *s;
int i;
bool is_string;
StringOrInt(char *s) : s(s), i(0), is_string(true) {}
StringOrInt(int i) : s(0), i(i), is_string(false) {}
bool isInt() { return !is_string; }
int asInt() { return i; }
char *asString() { return s; }
};
struct Foo {
int m1;
char *m2;
int m3;
Foo(int arg1, StringOrInt arg2 = "arg2", int arg3 = 1) : m1(arg1) {
if (arg2.isInt()) {
arg3 = arg2.asInt();
arg2 = "arg2";
}
m2 = arg2.asString();
m3 = arg3;
}
void print() {
std::cout << m1 << " " << m2 << " " << m3 << "\n";
}
};
int main() {
Foo(1, "HelloWorld").print();
Foo(1, 2).print();
}
Обратите внимание, что с GCC это генерирует предупреждения, поскольку преобразование строкового литерала в неконстантный char*
устарело и неразумно. Но это то, что вы просили, и исправить это так, чтобы параметры char*
и элемент данных были const char*
, достаточно просто.
Существенным недостатком является то, что это не мешает вам писать Foo(1,2,3)
. Чтобы проверить это во время компиляции, я думаю, вам нужно несколько конструкторов. Чтобы проверить это во время выполнения, вы можете преобразовать третий параметр в другой класс, DefaultOrInt
, где Default
- это тип, используемый только для этой цели, поддерживая только одно значение, используемое в качестве значения по умолчанию arg3
. Тогда, если arg2.isInt()
верно, проверьте arg3.isInt()
ложно, а если нет, бросьте logic_error
.