应用中的歧义

Ambiguity within apply

我在使用 apply 函数时遇到以下代码中的歧义问题。它基于 Whosebug 问题 here.

1) 我有一个助手 class,因为模板函数作为指针是不允许的:

template<typename TT, class...Ts>
struct selector_helper
{
    static TT doSelect(Ts&&... params)
    {
        return iSelectable<Ts...>::select<TT>(std::forward<Ts>(params)...);
    }
};

我尝试运行应用函数,但是运行遇到了问题。我尝试了两个代码,但没有一个成功:

2.1) 错误:应用:2 个重载中的 none 可以转换所有参数类型

boost::tuple<Ts...> tpl;
return apply<T, Ts...>(selector_helper<T, Ts...>::doSelect, tpl);

2.2) 这里我得到两个错误:

编辑:更多解释:

两个例子都运行内嵌在select方法中,它在class:

class database
{
    template<typename T, typename...Ts>
    T select_(const std::string& sql)
    {
        // apply examples
    }
};

并在这里打电话:

database db;
User result = db.select_<User, int, std::string, std::string>
    ("select id, email, name from credentials_tbl limit 1");

我错过了什么?

这里有一个完整的例子,我希望它包含所有内容: (当 运行 Microsoft Visual Studio 2013 我得到同样的错误)

// apply_test.cpp : Defines the entry point for the console application.
//

#include <iostream>
#include <boost/noncopyable.hpp>
#include <boost/enable_shared_from_this.hpp>
#include <boost/tuple/tuple.hpp>

using namespace boost;

/* apply methods from  */

// ------------- UTILITY---------------
template<int...> struct index_tuple{};

template<int I, typename IndexTuple, typename... Types>
struct make_indexes_impl;

template<int I, int... Indexes, typename T, typename ... Types>
struct make_indexes_impl<I, index_tuple<Indexes...>, T, Types...>
{
    typedef typename make_indexes_impl<I + 1, index_tuple<Indexes..., I>, Types...>::type type;
};

template<int I, int... Indexes>
struct make_indexes_impl<I, index_tuple<Indexes...> >
{
    typedef index_tuple<Indexes...> type;
};

template<typename ... Types>
struct make_indexes : make_indexes_impl<0, index_tuple<>, Types...>
{};




// ----------UNPACK TUPLE AND APPLY TO FUNCTION ---------




template<class Ret, class... Args, int... Indexes >
Ret apply_helper(Ret(*pf)(Args...), index_tuple< Indexes... >, tuple<Args...>&& tup)
{
    return pf(forward<Args>(get<Indexes>(tup))...);
}


template<class Ret, class ... Args>
Ret apply(Ret(*pf)(Args...), const tuple<Args...>&  tup)
{
    return apply_helper(pf, typename make_indexes<Args...>::type(),
        tuple<Args...>(tup));
}

template<class Ret, class ... Args>
Ret apply(Ret(*pf)(Args...), tuple<Args...>&&  tup)
{
    return apply_helper<Ret, Args...>(pf, typename make_indexes<Args...>::type(), forward<tuple<Args...>>(tup));
}

/* end of apply methods */



/* class iSelectable */
template <typename...> struct iSelectable;

template<class...Ts>
class iSelectable
{
public:

    template<typename T>
    static T select(Ts&&...params)
    {
        return T(std::forward<Ts>(params)...);
    }

};


/* selector_helper */
template<typename TT, class...Ts>
struct selector_helper
{
    static TT doSelect(Ts&&... params)
    {
        return iSelectable<Ts...>::select<TT>(std::forward<Ts>(params)...);
    }
};

class postgres_database_impl : private boost::noncopyable
    , public boost::enable_shared_from_this<postgres_database_impl>
{
public:

    template<typename T, typename...Ts>
    T select_(const std::string& sql)
    {

            boost::tuple<Ts...> tpl;            


            /* This is where my errors occur: */

            return apply(selector_helper<T, Ts...>::doSelect, tpl);

    }

};

typedef boost::shared_ptr<postgres_database_impl> DatabaseImpl;

class Database : private boost::noncopyable
{
public:


    template<typename T, typename...Ts>
    T select_(const std::string& sql)
    {
        return impl_->select_<T, Ts...>(sql);
    }



private:
    DatabaseImpl impl_;

};





class User : public iSelectable < int, std::string, std::string >
{
public:

    User(int id, const std::string& name, const std::string& surname)
    {
        /* only for testing purposes */
        std::cout << name << ", ";
        std::cout << name << ", ";
        std::cout << surname << std::endl;
    }
};


int _tmain(int argc, _TCHAR* argv[])
{

    Database db;
    User result = db.select_<User, int, std::string, std::string>
        ("select id, email, name from credentials_tbl limit 1");

    return 0;
}

无论问题的上下文如何,我通常希望 selector_helper 类型看起来更像:

template <typename...> struct iSelectable;

template<typename TT>
struct selector_helper
{
    template<class... Ts>
    static TT doSelect(Ts&&... params) {
        return iSelectable<Ts...>::template select<TT>(std::forward<Ts>(params)...);
    }
};

请注意嵌套 select 模板上的额外 template 限定条件。如果 select 是一种类型(我们怎么知道),您可能也需要 typenameWhere and why do I have to put the "template" and "typename" keywords?

更新

查看更完整的示例,正​​是这个问题。 do_select 的模板参数已明确指定:

return apply(selector_helper<T, Ts...>::doSelect, tpl);

这行不通,因为它抑制了模板参数推导,并且签名被强制为

User (&)(int&&, std::basic_string<char, std::char_traits<char>, std::allocator<char> >&&, std::basic_string<char, std::char_traits<char>, std::allocator<char> >&&)

当然,虽然元组实际上是

boost::tuples::tuple<int, std::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::basic_string<char, std::char_traits<char>, std::allocator<char> >, ...>&

您可以看到 Args....

的推导类型存在冲突

实际上我会通过不那么具体来简化这个:

template <class Ret, class Tuple, class... Args, int... Indexes>
Ret apply_helper(Ret (*pf)(Args...), index_tuple<Indexes...>, Tuple&& tup) {
    return pf(std::forward<Args>(get<Indexes>(std::forward<Tuple>(tup)))...);
}

template <class Ret, class Tuple, class... Args> 
Ret apply(Ret (*pf)(Args...), Tuple&& tup) {
    return apply_helper(pf, typename make_indexes<Args...>::type(), std::forward<Tuple>(tup));
}

这已经编译

Live On Coliru

// apply_test.cpp : Defines the entry point for the console application.
//
#include <iostream>
#include <boost/noncopyable.hpp>
#include <boost/enable_shared_from_this.hpp>
#include <boost/tuple/tuple.hpp>
#include <boost/make_shared.hpp>

#define _TCHAR char
using namespace boost;

/* apply methods from
 * 
 */

// ------------- UTILITY---------------
template <int...> struct index_tuple {};

template <int I, typename IndexTuple, typename... Types> struct make_indexes_impl;

template <int I, int... Indexes, typename T, typename... Types>
struct make_indexes_impl<I, index_tuple<Indexes...>, T, Types...> {
    typedef typename make_indexes_impl<I + 1, index_tuple<Indexes..., I>, Types...>::type type;
};

template <int I, int... Indexes> struct make_indexes_impl<I, index_tuple<Indexes...> > {
    typedef index_tuple<Indexes...> type;
};

template <typename... Types> struct make_indexes : make_indexes_impl<0, index_tuple<>, Types...> {};

// ----------UNPACK TUPLE AND APPLY TO FUNCTION ---------
    template <class Ret, class Tuple, class... Args, int... Indexes>
    Ret apply_helper(Ret (*pf)(Args...), index_tuple<Indexes...>, Tuple&& tup) {
        return pf(std::forward<Args>(get<Indexes>(std::forward<Tuple>(tup)))...);
    }

    template <class Ret, class Tuple, class... Args> 
    Ret apply(Ret (*pf)(Args...), Tuple&& tup) {
        return apply_helper(pf, typename make_indexes<Args...>::type(), std::forward<Tuple>(tup));
    }

/* end of apply methods */

/* class iSelectable */
template <typename...> struct iSelectable;

template <class... Ts> struct iSelectable {
    template <typename T> static T select(Ts &&... params) { return T(std::forward<Ts>(params)...); }
};

/* selector_helper */
template <typename TT, class... Ts> struct selector_helper {
    static TT doSelect(Ts &&... params) { return iSelectable<Ts...>::template select<TT>(std::forward<Ts>(params)...); }
};

class postgres_database_impl : private boost::noncopyable,
                               public boost::enable_shared_from_this<postgres_database_impl> 
{
  public:
    template <typename T, typename... Ts> T select_(const std::string &sql) {
        boost::tuple<Ts...> tpl { -123, "fame", "something" };

        /* This is where my errors occur: */
        return apply(selector_helper<T, Ts...>::doSelect, tpl);
        return {123, "name", "something"};
    }
};

typedef boost::shared_ptr<postgres_database_impl> DatabaseImpl;

class Database : private boost::noncopyable {
  public:
    template <typename T, typename... Ts> T select_(const std::string &sql) { return impl_->select_<T, Ts...>(sql); }

  private:
    DatabaseImpl impl_ = boost::make_shared<postgres_database_impl>();
};

class User : public iSelectable<int, std::string, std::string> {
  public:
    User(int id, std::string name, std::string surname) 
        : id(id), name(std::move(name)), surname(std::move(surname)) {
    }

  private:
    int id;
    std::string name;
    std::string surname;

    friend std::ostream& operator << (std::ostream& os, User const& user) {
        return os << user.id << ", " << user.name << ", " << user.surname << "\n";
    }
};

int main() {
    Database db;
    User result =
        db.select_<User, int, std::string, std::string>("select id, email, name from credentials_tbl limit 1");

    std::cout << "Result: " << result << "\n";
}

输出:

Result: -123, fame, something

我认为我看到了很多进一步简化的机会,但老实说,我需要更多地了解开始这一旅程的目标。