-1

下面是一个有缺陷的(和简化的)模板函数,它期望在模板 arg 上工作,该模板 arg 可以转换为预定义数量的类型之一。

它恰好是 2 种类型,但它更冷。

void do_something_type_specific( const int &unused ) { std::cout << 'i'; }
void do_something_type_specific( const std::string &unused ) { std::cout << 's'; }

template< typename Iterator >
void perform_work_on_a_range( Iterator begin, Iterator end )
{
    do_something_type_specific( *begin );
    // Perhaps more code...
}

这恰好在我的环境中产生了预期的结果。模板实例将成功编译,但前提*Iterator是生成的类型可转换为恰好其中一个选项。

但是,此代码不必要地要求执行转换,尽管unused未使用,但仍然存在 UB when begin == end.

如果没有这些问题,如何在 C++03 中实现这种行为?

4

4 回答 4

3

begin == end您可以尝试使用std::iterator_traits<>,而不是取消引用我导致未定义行为的迭代器 when 。例如:

#include <iterator>
#include <string>
#include <cstdio>

void do_something_type_specific(std::string const&) { printf("%s\n", __PRETTY_FUNCTION__); }
void do_something_type_specific(int const&) { printf("%s\n", __PRETTY_FUNCTION__); }

template<class T>
struct ProduceValue
{
    static T value;
};

template<class T>
T ProduceValue<T>::value;

// Specializations for types that can't be default constructed or must be initialized.
template<>
char* ProduceValue<char*>::value = "";

template< typename Iterator >
void perform_work_on_a_range( Iterator begin, Iterator end )
{
    typedef typename std::iterator_traits<Iterator>::value_type value_type;
    do_something_type_specific(ProduceValue<value_type>::value);
}

int main() {
    char** p = 0;
    perform_work_on_a_range(p, p);

    long* q = 0;
    perform_work_on_a_range(q, q);
}

输出:

void do_something_type_specific(const string&)
void do_something_type_specific(const int&)

唯一的不便是它ProduceValue<T>必须专门用于无法默认构造或由于其他原因(如char*)而必须初始化的类型。

于 2013-03-06T17:00:01.703 回答
2

您可以使用一个boost::is_convertible元函数来确定是否可以将类型 T 转换为其他类型 U。

其次,对于begin == end,只需插入运行时检查。

于 2013-03-06T16:52:51.700 回答
1

问题中的有问题的代码试图利用模板参数函数参数的特性。

函数参数允许类型转换,但需要类型的实例化。模板参数不需要实例化,也不需要进行类型转换。

下面的模式使用 Boost 的enable_ifandis_convertible允许编译器选择模板函数,就好像模板参数支持与函数参数相同的类型转换规则。 (感谢@dhavenith 的建议)

#include <boost/utility.hpp>
#include <boost/type_traits.hpp>

// enable_if_c makes the return type either void or a Substitution Failure.
template < typename T>
typename boost::enable_if_c<boost::is_convertible<T,int>::value>::type
do_something_type_specific()
{
  std::cout << 'i';
}

template < typename T>
typename boost::enable_if_c<boost::is_convertible<T,std::string>::value>::type
do_something_type_specific()
{
  std::cout << 's';
}

template< typename Iterator >
void perform_work_on_a_range( Iterator begin, Iterator end )
{
    // This code is from @MaximYegorushkin's answer.  Vote him up :)
    typedef typename std::iterator_traits<Iterator>::value_type value_type;
    do_something_type_specific<value_type>();
    // Perhaps more code...
}

这已通过@MaximYegorushkin 的示例主程序进行了验证。

int main() {
    char** p = 0;
    perform_work_on_a_range(p, p);

    long* q = 0;
    perform_work_on_a_range(q, q);
}

输出:

si
于 2013-03-06T18:52:22.080 回答
0

你可能想做这样的事情:

template <typename T>
void do_something_type_specific() {}
template <>
void do_something_type_specific<int>() {...}
template <typename Iterator>
void perform_work_on_a_range(Iterator begin, Iterator end) {
    do_something_type_specific<typename Iterator::value_type>();
}
于 2013-03-06T17:24:53.087 回答