从C ++

时间:2017-07-07 13:50:47

标签: c++ templates if-statement

我正在尝试使用模板编写一个泛型函数,它能够返回bool,integer或char *或string。

template<typename entryType>
entryType getEntry(xml_node node, const char* entryKey)
{
    ...

    if (is_same<entryType, bool>::value) {
         return boolvalue; //returning a boolean
    }
    else if(is_same<entryType, int>::value) {
         return a; //this is an integer
    }
    else if (is_same<entryType, char*>::value) {
         return result; //this is a char*
    }
}

我希望能够称之为:

bool bPublisher = getEntry<bool>(node, "Publisher");
int QoS = getEntry<int>(node, "QualityOfService");
char* sBrokerUrl = getEntry<char*>(node, "BrokerUrl");

作为char *的替代,字符串也可以:

string sBrokerUrl = getEntry<string>(node, "BrokerUrl");

我得到的错误如下:“无法从'bool'转换为'char *'。我理解问题,编译器无法检测到代码执行分支取决于我给出的类型。我只是不能找到解决方案。有人可以帮助我吗?谢谢。

5 个答案:

答案 0 :(得分:3)

从C ++ 17开始,您可以使用constexpr if;其条件部分将在编译时进行评估,如果结果为true,则将丢弃statement-false部分(否则为statement-true部分)。 (因此不会导致错误。)例如

if constexpr (is_same<entryType, bool>::value) {
     return boolvalue; //returning a boolean
}
else if constexpr (is_same<entryType, int>::value) {
     return a; //this is an integer
}
else if constexpr (is_same<entryType, char*>::value) {
     return result; //this is a char*
}

LIVE

答案 1 :(得分:2)

对于旧版本的C ++,您可以通过转发到其中一个重载函数来解决这个问题,这些函数通过引用传递的参数返回结果:

template<typename entryType>
entryType getEntry(xml_node node, const char* entryKey)
{
    entryType result = entryType();
    this->getEntry(node, entryKey, result);
    return result;
}

void getEntry(xml_node node, const char* entryKey, bool& result);
void getEntry(xml_node node, const char* entryKey, int& result);
void getEntry(xml_node node, const char* entryKey, char const *& result);

或者您可以使用std::enable_if(自C ++ 11起):

template<typename entryType>
typename std::enable_if<std::is_same<entryType, bool>::value, entryType>::type
    getEntry(xml_node node, const char* entryKey) {
    ...
}

但第一个解决方案IMO更具可读性。如果您不想公开它们,可以将重载函数设为私有。

答案 2 :(得分:1)

就像@ tobi303在评论中所说,你应该专门化模板。 不需要花哨的SFINAE或其他技巧。

#include <iostream>
#include <type_traits>

using namespace std;

template<typename entryType>
entryType getEntry(const char* entryKey);

template <>
int getEntry<int>(const char* entryKey)
{
    return 1;
}
template <>
bool getEntry<bool>(const char* entryKey)
{
    return false;
}
template <>
string getEntry<string>(const char* entryKey)
{
    return "asd";
}

int main() {
    bool bPublisher = getEntry<bool>("Publisher");
    int QoS = getEntry<int>("QualityOfService");
    string sBrokerUrl = getEntry<string>("BrokerUrl");

    cout << bPublisher << '\n' << QoS << '\n'<< sBrokerUrl << '\n';
}

DEMO:https://wandbox.org/permlink/kyLuPyblb4zBi9fE

答案 3 :(得分:0)

我认为我倾向于利用std::tuple已经非常出色的功能。

将其与标记值结合使用,可以轻松地为此类事物生成富有表现力,类型安全的代码。

#include <iostream>
#include <tuple>


template<class Tag, class Type>
struct xmlvalue : Type
{
    using Type::Type;
};

template<class Tag> struct xmlvalue<Tag, bool>
{
    xmlvalue(bool v) : value_(v) {}

    operator bool&() { return value_; }
    operator bool const&() const { return value_; }

private:
    bool value_;
};

template<class Tag> struct xmlvalue<Tag, int>
{
    xmlvalue(int v) : value_(v) {}

    operator int&() { return value_; }
    operator int const&() const { return value_; }

private:
    int value_;
};

struct is_publisher_tag {};
struct qos_tag {};
struct broker_url_tag {};

using is_publisher = xmlvalue<is_publisher_tag, bool>;
using qos = xmlvalue<qos_tag, int>;
using broker_url = xmlvalue<broker_url_tag, std::string>;


struct quote : std::tuple<is_publisher , qos, broker_url >
{
    using std::tuple<is_publisher , qos, broker_url >::tuple;
};

int main() {

    auto q1 = quote(true, 100, "http:://foo.com");
    auto q2 = quote(false, 50, "http:://bar.com");

    std::cout << std::get<broker_url>(q1) << ", " << std::get<qos>(q1) << ", " << std::get<is_publisher>(q1) << std::endl;
    std::cout << std::get<broker_url>(q2) << ", " << std::get<qos>(q2) << ", " << std::get<is_publisher>(q2) << std::endl;

    return 0;
}

预期产出:

http:://foo.com, 100, 1
http:://bar.com, 50, 0

答案 4 :(得分:0)

如果您无法使用C ++ 17,那么模板专业化可能会做您想做的事情:

template<typename entryType>
entryType getEntry(xml_node node, const char* entryKey) {}

template<>
bool getEntry<bool>(xml_node node, const char* entryKey) {
   return true;
}

template<>
int getEntry<int>(xml_node node, const char* entryKey) {
   return 1;
}

您可以将任何共享代码放在从每个专业化调用的辅助函数中:

void shared_code(xml_node node, const char* entryKey) {
   // ...
}

template<>
bool getEntry<bool>(xml_node node, const char* entryKey) {
   shared_code(node, entryKey);
   return true;
}

template<>
int getEntry<int>(xml_node node, const char* entryKey) {
   shared_code(node, entryKey);
   return 1;
}