class Test
{
public:
SOMETHING DoIt(int a)
{
float FLOAT = 1.2;
int INT = 2;
char CHAR = 'a';
switch(a)
{
case 1: return INT;
case 2: return FLOAT;
case 3: return CHAR;
}
}
};
int main(int argc, char* argv[])
{
Test obj;
cout<<obj.DoIt(1);
return 0;
}
现在,使用a = 1意味着我需要返回一个整数等的知识,无论如何Doit()可以返回一个变量数据类型的变量吗?
基本上,我将如何替换 SOMETHING ?
PS:我正在尝试寻找一种替代方法来返回包含这些数据类型的结构/联合。
答案 0 :(得分:25)
您可以使用boost::any
或boost::variant
来执行您想要的操作。我推荐boost::variant
,因为您知道要返回的类型集合。
这是一个非常简单的示例,但您可以使用variant
执行更多操作。查看参考资料以获取更多示例:)
#include "boost/variant.hpp"
#include <iostream>
typedef boost::variant<char, int, double> myvariant;
myvariant fun(int value)
{
if(value == 0)
{
return 1001;
}
else if(value == 1)
{
return 3.2;
}
return 'V';
}
int main()
{
myvariant v = fun(0);
std::cout << v << std::endl;
v = fun(1);
std::cout << v << std::endl;
v = fun(54151);
std::cout << v << std::endl;
}
输出:
1001
3.2
V
我会使用boost::variant
而不是union
,因为您无法在union
内使用非POD类型。另外,如果你不知道你正在处理的类型,boost::any
是很好的。否则,我会使用boost::variant
,因为它更有效,更安全。
回答已修改的问题:如果您不想使用代码发送Boost
,请查看bcp
。来自同一链接的bcp
说明:
bcp实用程序是一个工具 提取Boost的子集,就是这样 对于想要的Boost作者很有用 分别分发他们的库 来自Boost,以及Boost用户 想要分发Boost的子集 与他们的应用。
bcp还可以报告哪些部分 提升您的代码依赖于,和 那些使用的许可证 的依赖关系。
答案 1 :(得分:8)
C ++是一种强类型语言,没有未知类型的概念。你可以尝试使用boost :: any,它可以(有点)指定任何类型。不过,我会质疑你的功能设计。
答案 2 :(得分:5)
如果您在编译时知道类型,则可以使用模板。如果type取决于运行时,那么使用模板不是一种选择。
class Test
{
template<int> struct Int2Type {};
template<> struct Int2Type<1> { typedef int value_type; };
template<> struct Int2Type<2> { typedef float value_type; };
template<> struct Int2Type<3> { typedef char value_type; };
public:
template<int x> typename Int2Type<x>::value_type DoIt() {}; // error if unknown type used
template<> typename Int2Type<1>::value_type DoIt<1>() { return 2; };
template<> typename Int2Type<2>::value_type DoIt<2>() { return 1.2f; };
template<> typename Int2Type<3>::value_type DoIt<3>() { return 'a'; };
};
int main()
{
Test obj;
cout << obj.DoIt<2>();
return 0;
}
答案 3 :(得分:3)
使用boost::any:
boost::any DoIt(int a)
{
float FLOAT = 1.2;
int INT = 2;
char CHAR = 'a';
switch(a)
{
case 1: return boost::any(INT);
case 2: return boost::any( FLOAT);
case 3: return boost::any( CHAR);
}
}
答案 4 :(得分:3)
您可以使用包含void*
的结构,指向要返回的值以及指示要返回的对象大小的size_t
。像这样:
struct Something {
void *value;
size_t size;
};
请记住,void*
应该指向驻留在堆上的值(即使用new
或malloc
动态分配),并且调用者应该负责释放已分配的对象。 / p>
话虽如此,我认为这总体上是一个坏主意。
编辑:您可能还需要考虑在上述结构中包含一个标志,指示返回的内容,以便调用者可以理解它,除非调用者知道期望的类型。
答案 5 :(得分:3)
实现类似这样的东西的常用方法是C,它在C ++中并不总是有效,是一个union和一个类型字段:
enum SomeType { INT, FLOAT, CHAR };
struct Something
{
SomeType type;
union
{
int i;
float f;
char c;
};
};
Something DoIt(int a)
{
Something s;
switch (a)
{
case 1:
s.type = INT;
s.i = 2;
break;
case 2:
s.type = FLOAT;
s.f = 1.2;
break;
case 3:
s.type = CHAR;
s.c = 'a';
break;
default:
// ???
}
return s;
}
当一个可能的值类型是一个具有非平凡构造函数的类时,这在C ++中不起作用,因为它并不总是清楚应该调用哪个构造函数。 Boost.Variant使用此方法的更复杂版本为C ++中的任何值类型提供此类构造。
答案 6 :(得分:3)
编辑:boost ::任何使用bcp(感谢AraK)似乎是迄今为止最好的解决方案,但有可能证明(在某种程度上)没有ANSI C ++解决方案来解决这个问题吗?
你似乎对这里的术语感到有些困惑。
首先,我们称之为ISO C ++,不是吗?它在1998年由ISO标准化,从那时起,人们在谈论“标准C ++”时就提到了这一点。 现在,“ANSI C ++解决方案”是什么意思?
我无法想象你会寻找什么样的“证明”。 C ++是散文形式的文档。它不是一个数学方程式。它不能被“证明”,除非说“去读标准”。证明在语言或标准库中定义 的内容很简单 - 只需指出标准中描述的位置即可。但证明不是的东西基本上是不可能的 - 除了枚举标准的每个单个句子,并记录它们都没有描述你要找的东西。我怀疑你会发现有人愿意为你做 。
无论如何,使用Boost正确的标准C ++解决方案 。 它不是一个重量级的解决方案。 Boost非常轻量级,因为您可以将完全包含在您需要的位中,而不依赖于库集合的其余部分。
根据您的描述(广泛用户群的轻量级应用程序),没有理由不使用Boost。它可以简化您的代码并减少因重新发明轮子而导致的错误数量。分发已编译的可执行文件时,它的成本为零。 Boost.Any
库与Boost一样,仅限于标头,并且只是编译到您的可执行文件中。不需要分发单独的库。
试图重新发明轮子没有任何好处。您的可执行文件将不会更小或更高效,但它将更多的错误。
而且我愿意打赌你自己酿造的解决方案不是ANSI C ++。它将依赖某种形式的未定义行为。如果你想要ANSI-C ++解决方案,最好的选择是Boost。
答案 7 :(得分:1)
你可以使用联盟:
typedef union {
int i;
float f;
char c;
} retType;
retType DoIt(int a){
retType ret;
float FLOAT = 1.2;
int INT = 2;
char CHAR = 'a';
switch(a)
{
case 1: ret.i = INT; break;
case 2: ret.f = FLOAT; break;
case 3: ret.c = CHAR; break;
}
return ret;
}
答案 8 :(得分:0)
Adobe源库也有adobe::any_regular_t
,只要它为Regular概念建模,就可以存储任何类型。您可以像使用boost::any
一样包装返回值。 (链接页面上还有关于adobe::any_regular_t
与boost::any
的区别的文档 - 当然,您选择的类型应取决于代码的要求。)
答案 9 :(得分:0)
您可以通过引用传递而不是typesave并检查它是否同时工作,也不会涉及任何其他库(您的ansi C ++解决方案):
bool DoIt (int i, int & r1)
{
if (i==1) {r1 = 5; return true}
return false;
}
bool DoIt (int i, double & r2)
{
if (i==2) {r2 = 1.2; return true}
return false;
}
...
我发现这种解决方案在设计方面往往更加清洁。不幸的是,funciton签名不允许多种类型作为返回类型,但这样你就可以传递任何东西。
答案 10 :(得分:0)
从C ++ 17开始,有std::any
和std::variant
,这意味着您不需要第三方库。从@Arak的答案中,将对代码进行如下修改。
#include <variant>
#include <any>
#include <iostream>
typedef std::variant<char, int, double> myvariant;
myvariant fun(int value)
{
if(value == 0)
{
return 1001;
}
else if(value == 1)
{
return 3.2;
}
return 'V';
}
int main()
{
myvariant v = fun(0);
std::cout << v << std::endl;
v = fun(1);
std::cout << v << std::endl;
v = fun(54151);
std::cout << v << std::endl;
}
答案 11 :(得分:-1)
如果用户知道放入了什么,您可以使用模板来解决此问题。如果没有,我想不出任何解决方案。
答案 12 :(得分:-1)
我认为问题在于这个功能设计。你试过重载吗?
class Test
{
public:
int DoIt(int a) {
int INT = 2;
return INT;
}
float DoIt(float a) {
float FLOAT = 1.2;
return FLOAT;
}
char DoIt(char a) {
char CHAR = 'a';
return CHAR;
}
};
int main(int argc, char* argv[])
{
Test obj;
//....
switch(a)
case 1:
cout<< obj.DoIt(1);
break;
case 2:
cout<< obj.DoIt(1.01);
break;
case 3:
cout<< obj.DoIt("1");
break;
return 0;
}
在DoIt函数内部,您可以放置更多代码,并让它们调用其他函数,以避免重复代码。
答案 13 :(得分:-3)
SOMETHING = void *
您必须转换返回的值,因此您必须知道返回的内容。
void* DoIt(int a)
{
float FLOAT = 1.2;
int INT = 2;
char CHAR = 'a';
switch(a)
{
case 1: return &INT;
case 2: return &FLOAT;
case 3: return &CHAR;
}
}